26 #if defined (HAVE_CONFIG_H)
30 #if defined (HAVE_QSCINTILLA)
32 #include <Qsci/qscilexer.h>
35 #include <QKeySequence>
36 #include <QMessageBox>
40 #include <QVBoxLayout>
41 #if defined (HAVE_QSCI_QSCILEXEROCTAVE_H)
42 # define HAVE_LEXER_OCTAVE 1
43 # include <Qsci/qscilexeroctave.h>
44 #elif defined (HAVE_QSCI_QSCILEXERMATLAB_H)
45 # define HAVE_LEXER_MATLAB 1
46 # include <Qsci/qscilexermatlab.h>
48 #include <Qsci/qscicommandset.h>
49 #include <Qsci/qscilexerbash.h>
50 #include <Qsci/qscilexerbatch.h>
51 #include <Qsci/qscilexercpp.h>
52 #include <Qsci/qscilexerdiff.h>
53 #include <Qsci/qscilexerperl.h>
63 #include "builtin-defun-decls.h"
76 is_end (
const QString& candidate,
const QString& opening)
82 if (candidate ==
"until")
87 if (candidate ==
"end")
93 if (candidate ==
"catch" || candidate ==
"end_try_catch")
96 else if (opening ==
"unwind_protect")
98 if (candidate ==
"unwind_protect_cleanup"
99 || candidate ==
"end_unwind_protect")
102 else if (candidate ==
"end" + opening)
104 else if (opening ==
"if" && candidate ==
"else")
113 :
QsciScintilla (p), m_octave_qobj (oct_qobj), m_word_at_cursor (),
114 m_selection (), m_selection_replacement (), m_selection_line (-1),
115 m_selection_col (-1), m_indicator_id (1)
117 connect (
this, SIGNAL (textChanged (
void)),
120 connect (
this, SIGNAL (cursorPositionChanged (
int,
int)),
124 QTemporaryFile*,
bool,
bool)),
126 QTemporaryFile*,
bool,
bool)),
127 Qt::QueuedConnection);
130 QsciCommandSet *cmd_set = standardCommands ();
133 SendScintilla (SCI_SETBUFFEREDDRAW,
false);
135 #if defined (HAVE_QSCI_VERSION_2_6_0)
137 cmd_set->find (QsciCommand::SelectionCopy)->setKey (0);
138 cmd_set->find (QsciCommand::SelectionCut)->setKey (0);
139 cmd_set->find (QsciCommand::Paste)->setKey (0);
140 cmd_set->find (QsciCommand::SelectAll)->setKey (0);
141 cmd_set->find (QsciCommand::SelectionDuplicate)->setKey (0);
142 cmd_set->find (QsciCommand::LineTranspose)->setKey (0);
143 cmd_set->find (QsciCommand::Undo)->setKey (0);
144 cmd_set->find (QsciCommand::Redo)->setKey (0);
145 cmd_set->find (QsciCommand::SelectionUpperCase)->setKey (0);
146 cmd_set->find (QsciCommand::SelectionLowerCase)->setKey (0);
147 cmd_set->find (QsciCommand::ZoomIn)->setKey (0);
148 cmd_set->find (QsciCommand::ZoomOut)->setKey (0);
149 cmd_set->find (QsciCommand::DeleteWordLeft)->setKey (0);
150 cmd_set->find (QsciCommand::DeleteWordRight)->setKey (0);
151 cmd_set->find (QsciCommand::DeleteLineLeft)->setKey (0);
152 cmd_set->find (QsciCommand::DeleteLineRight)->setKey (0);
153 cmd_set->find (QsciCommand::LineDelete)->setKey (0);
154 cmd_set->find (QsciCommand::LineCut)->setKey (0);
155 cmd_set->find (QsciCommand::LineCopy)->setKey (0);
159 for (
int i = 0; i < cmd_list.length (); i++)
161 int cmd_key = cmd_list.at (i)->key ();
172 case Qt::Key_Z |
Qt::CTRL | Qt::SHIFT :
174 case Qt::Key_U |
Qt::CTRL | Qt::SHIFT :
177 case Qt::Key_Backspace |
Qt::CTRL | Qt::SHIFT :
178 case Qt::Key_Delete |
Qt::CTRL | Qt::SHIFT :
179 case Qt::Key_K | Qt::META :
182 case Qt::Key_L |
Qt::CTRL | Qt::SHIFT :
184 case Qt::Key_T |
Qt::CTRL | Qt::SHIFT :
185 cmd_list.at (i)->setKey (0);
190 #if defined (Q_OS_MAC)
194 for (
int i = 0; i < cmd_list_mac.length (); i++)
197 int key = cmd_list_mac.at (i)->key ();
199 if (
static_cast<int> (key | Qt::META) == key
200 &&
static_cast<int> (key |
Qt::CTRL) != key)
202 else if (
static_cast<int> (key |
Qt::CTRL) == key)
205 cmd_list_mac.at (i)->setKey (key);
208 key = cmd_list_mac.at (i)->alternateKey ();
210 if (
static_cast<int> (key | Qt::META) == key
211 &&
static_cast<int> (key |
Qt::CTRL) != key)
213 else if (
static_cast<int> (key |
Qt::CTRL) == key)
216 cmd_list_mac.at (i)->setAlternateKey (key);
222 m_indicator_id = indicatorDefine (QsciScintilla::StraightBoxIndicator);
248 #if defined (HAVE_QSCI_VERSION_2_6_0)
249 QPoint global_pos, local_pos;
250 QMenu *context_menu = createStandardContextMenu ();
252 bool in_left_margin =
false;
255 if (e->reason () == QContextMenuEvent::Mouse)
258 global_pos = e->globalPos ();
259 local_pos = e->pos ();
260 if (e->x () < marginWidth (1) + marginWidth (2))
261 in_left_margin =
true;
267 QRect editor_rect = geometry ();
268 editor_rect.moveTopLeft
269 (parentWidget ()->mapToGlobal (editor_rect.topLeft ()));
270 if (! editor_rect.contains (global_pos))
271 global_pos = editor_rect.topLeft ();
274 #if defined (HAVE_QSCI_VERSION_2_6_0)
275 if (! in_left_margin)
282 context_menu->addSeparator ();
286 QString lexer_name =
lexer ()->lexer ();
287 if (lexer_name ==
"octave" || lexer_name ==
"matlab")
294 context_menu->addAction (tr (
"Documentation on")
302 #if defined (HAVE_QSCI_VERSION_2_6_0)
308 for (
auto *a : all_actions)
309 context_menu->removeAction (a);
312 = context_menu->addAction (tr (
"dbstop if ..."),
this,
314 act->setData (local_pos);
319 context_menu->exec (global_pos);
342 if (hasSelectedText ())
355 long position = SendScintilla (SCI_GETCURRENTPOS);
356 long point_x = SendScintilla (SCI_POINTXFROMPOSITION,0,position);
357 long point_y = SendScintilla (SCI_POINTYFROMPOSITION,0,position);
358 *local_pos = QPoint (point_x,point_y);
359 *global_pos = mapToGlobal (*local_pos);
365 QPoint global_pos, local_pos;
368 QString lexer_name =
lexer ()->lexer ();
369 return ((lexer_name ==
"octave" || lexer_name ==
"matlab")
376 int end_pos =
text ().length ();
377 int end_line, end_col;
378 lineIndexFromPosition (end_pos, &end_line, &end_col);
388 *pos = SendScintilla (QsciScintillaBase::SCI_GETCURRENTPOS);
389 *
line = SendScintilla (QsciScintillaBase::SCI_LINEFROMPOSITION, *pos);
390 *col = SendScintilla (QsciScintillaBase::SCI_GETCOLUMN, *pos);
396 int lexer = SendScintilla (SCI_GETLEXER);
400 #if defined (HAVE_LEXER_OCTAVE) || defined (HAVE_LEXER_MATLAB)
401 #if defined (HAVE_LEXER_OCTAVE)
446 return QStringList (
"#");
449 return QStringList (
"//");
452 return QStringList (
"REM ");
455 return QStringList (
"%");
465 position = SendScintilla (QsciScintillaBase::SCI_GETCURRENTPOS) - 2;
469 return SendScintilla (QsciScintillaBase::SCI_GETSTYLEAT, position);
475 int lexer = SendScintilla (QsciScintillaBase::SCI_GETLEXER);
482 || style == QsciLexerCPP::CommentLineDoc)
484 || style == QsciLexerCPP::CommentDoc
485 || style == QsciLexerCPP::CommentDocKeyword
486 || style == QsciLexerCPP::CommentDocKeywordError));
488 #if defined (HAVE_LEXER_MATLAB)
492 #if defined (HAVE_LEXER_OCTAVE)
516 int line,
int ind_char_width)
520 QRegExp bkey = QRegExp (
"^[\t ]*(if|for|while|switch"
521 "|do|function|properties|events|classdef"
522 "|unwind_protect|try"
531 QRegExp ekey = QRegExp (
"(?:(?:['\"][^'\"]*['\"])?[^%#]*)*"
532 "(\\w+)[ \t;\r\n]*(?:[%#].*)?$");
534 int bpos = bkey.indexIn (prevline, 0);
542 epos = ekey.indexIn (prevline, bpos);
543 QString first_word = bkey.cap(1);
544 bool inline_end = (epos > -1) &&
is_end (ekey.cap(1), first_word);
546 if (do_smart_indent && ! inline_end)
550 setCursorPosition (
line+1, indentation (
line+1) / ind_char_width);
555 && ! first_word.contains (QRegExp (
"(?:case|otherwise|unwind_protect_cleanup)")))
564 QRegExp mkey = QRegExp (
"^[\t ]*(?:else|elseif|catch|unwind_protect_cleanup)"
566 if (prevline.contains (mkey))
568 int prev_ind = indentation (
line-1);
569 int act_ind = indentation (
line);
571 if (prev_ind == act_ind)
573 else if (prev_ind > act_ind)
575 setIndentation (
line+1, prev_ind);
576 setCursorPosition (
line+1, prev_ind);
581 QRegExp case_key = QRegExp (
"^[\t ]*(?:case|otherwise)[\r]?[\t #%\n]");
582 if (prevline.contains (case_key) && do_smart_indent)
585 int act_ind = indentation (
line);
587 if (last_line.contains (
"switch"))
590 act_ind = indentation (
line+1);
595 setIndentation (
line+1, act_ind);
596 setCursorPosition (
line+1, act_ind);
599 ekey = QRegExp (
"^[\t ]*(?:end|endif|endfor|endwhile|until|endfunction"
600 "|end_try_catch|end_unwind_protect)[\r]?[\t #%\n(;]");
601 if (prevline.contains (ekey))
603 if (indentation (
line-1) <= indentation (
line))
607 setCursorPosition (
line+1,
618 QRegExp blank_line_regexp = QRegExp (
"^[\t ]*$");
621 QRegExp end_word_regexp
622 = QRegExp (
"(?:(?:['\"][^'\"]*['\"])?[^%#]*)*"
623 "(?:end\\w*)[\r\n\t ;]*(?:[%#].*)?$");
625 QRegExp begin_block_regexp
626 = QRegExp (
"^[\t ]*(?:if|elseif|else"
627 "|for|while|do|parfor"
628 "|switch|case|otherwise"
630 "|classdef|properties|events|enumeration|methods"
631 "|unwind_protect|unwind_protect_cleanup|try|catch)"
634 QRegExp mid_block_regexp
635 = QRegExp (
"^[\t ]*(?:elseif|else"
637 "|unwind_protect_cleanup|catch)"
640 QRegExp end_block_regexp
641 = QRegExp (
"^[\t ]*(?:end"
642 "|end(for|function|if|parfor|switch|while"
643 "|classdef|enumeration|events|methods|properties)"
644 "|end_(try_catch|unwind_protect)"
648 QRegExp case_block_regexp
649 = QRegExp (
"^[\t ]*(?:case|otherwise)"
652 int indent_column = -1;
653 int indent_increment = indentationWidth ();
654 bool in_switch =
false;
660 if (blank_line_regexp.indexIn (line_text) < 0)
667 indent_column = indentation (
line);
669 if (begin_block_regexp.indexIn (line_text) > -1)
671 indent_column += indent_increment;
672 if (line_text.contains (
"switch"))
680 if (indent_column < 0)
681 indent_column = indentation (lineFrom);
688 if (end_block_regexp.indexIn (line_text) > -1)
690 indent_column -= indent_increment;
691 if (line_text.contains (
"endswitch"))
695 indent_column -= indent_increment;
700 if (mid_block_regexp.indexIn (line_text) > -1)
701 indent_column -= indent_increment;
703 if (case_block_regexp.indexIn (line_text) > -1)
705 if (case_block_regexp.indexIn (prev_line) < 0
706 && !prev_line.contains(
"switch"))
707 indent_column -= indent_increment;
711 setIndentation (
line, indent_column);
714 int bpos = begin_block_regexp.indexIn (line_text);
718 int epos = end_word_regexp.indexIn (line_text, bpos);
720 indent_column += indent_increment;
721 if (line_text.contains (
"switch"))
725 if (blank_line_regexp.indexIn (line_text) < 0)
726 prev_line = line_text;
743 QToolTip::hideText ();
783 QMessageBox::critical (
this, tr (
"Octave Editor"),
784 tr (
"Creating temporary files failed.\n"
785 "Make sure you have write access to temp. directory\n"
787 "\"Run Selection\" requires temporary files.").arg (QDir::tempPath ()));
796 QString code = QString ();
797 QString hist = QString ();
800 QStringList lines = selectedText ().split (QRegExp (
"[\r\n]"),
801 #
if defined (HAVE_QT_SPLITBEHAVIOR_ENUM)
804 QString::SkipEmptyParts);
806 for (
int i = 0; i < lines.count (); i++)
808 QString
line = lines.at (i);
809 if (
line.trimmed ().isEmpty ())
811 QString line_escaped =
line;
812 line_escaped.replace (QString (
"'"), QString (
"''"));
813 QString line_history =
line;
816 QString next_bp_quiet;
817 QString next_bp_quiet_reset;
818 if (
line.contains (
"keyboard"))
822 next_bp_quiet =
"__db_next_breakpoint_quiet__;\n";
823 next_bp_quiet_reset =
"__db_next_breakpoint_quiet__(false);\n";
827 code += next_bp_quiet +
line + next_bp_quiet_reset +
"\n";
828 hist += line_history +
"\n";
834 QPointer<QTemporaryFile> tmp_file
837 bool tmp = (tmp_file && tmp_file->open ());
848 QPointer<QTemporaryFile> tmp_hist
851 tmp = (tmp_hist && tmp_hist->open ());
867 std::string opt =
"-r";
880 ([
this, tmp_file, tmp_hist, show_dbg_file] (
interpreter& interp)
884 std::string file = tmp_file->fileName ().
toStdString ();
892 bool dbg = ovl_dbg(0).bool_value ();
895 ovl_auto_repeat = Fauto_repeat_debug_command (interp,
ovl (
false), 1);
896 bool auto_repeat = ovl_auto_repeat(0).bool_value ();
910 std::list<frame_info> stack = e.stack_info ();
915 if (stack.size () < 2)
917 QRegExp rx (
"source: error sourcing file [^\n]*$");
918 if (new_msg.contains (rx))
921 new_msg.replace (rx,
"error sourcing selected code");
929 rx_list <<
"near line (\\d+),[^\n]*\n";
930 rx_list <<
"near line (\\d+),[^\n]*$";
932 QStringList replace_list;
933 replace_list <<
"\n";
936 for (
int i = 0; i < rx_list.length (); i++)
939 rx = QRegExp (rx_list.at (i));
940 pos = rx.indexIn (new_msg, pos);
943 err_line = rx.cap (1).toInt ();
944 new_msg = new_msg.replace (rx, replace_list.at (i));
951 if (stack.size () > 0)
960 octave::execution_exception ee (e.err_type (),e.identifier (),
961 new_msg.toStdString (), stack);
985 QTemporaryFile* tmp_file, QTemporaryFile* tmp_hist,
986 bool dbg,
bool auto_repeat)
1005 Fauto_repeat_debug_command (interp,
ovl (auto_repeat));
1015 #if defined (HAVE_QSCI_VERSION_2_6_0)
1016 QAction *action = qobject_cast<QAction *>(sender ());
1017 QPoint local_pos = action->data ().value<QPoint> ();
1020 int margins = marginWidth (1) + marginWidth (2) + marginWidth (3);
1021 local_pos = QPoint (margins + 1, local_pos.y ());
1029 #if defined (HAVE_QSCI_VERSION_2_6_0)
1036 emit
status_update (isUndoAvailable (), isRedoAvailable ());
1054 emit
status_update (isUndoAvailable (), isRedoAvailable ());
1056 QsciScintilla::focusInEvent (focusEvent);
1066 QKeySequence keyseq = Qt::SHIFT + Qt::Key_Return;
1068 QString msg = (tr (
"Press '%1' to replace all occurrences of '%2' with '%3'.")
1069 . arg (keyseq.toString ())
1078 QFontMetrics ttfm (QToolTip::font ());
1083 global_pos += QPoint (2*ttfm.maxWidth (), -3*ttfm.height ());
1085 QToolTip::showText (global_pos, msg);
1091 QsciScintilla::keyPressEvent (key_event);
1094 int key = key_event->key ();
1095 Qt::KeyboardModifiers modifiers = key_event->modifiers ();
1097 if (key == Qt::Key_Return && modifiers == Qt::ShiftModifier)
1105 int first_line = firstVisibleLine ();
1108 bool find_result_available
1117 #
if defined (HAVE_QSCI_VERSION_2_6_0)
1122 while (find_result_available)
1130 int new_line, new_col;
1133 find_result_available
1142 #
if defined (HAVE_QSCI_VERSION_2_6_0)
1150 setFirstVisibleLine (first_line);
1151 setCursorPosition (
line, col);
1167 bool cancel_replacement =
false;
1169 if (key == Qt::Key_Backspace)
1172 cancel_replacement =
true;
1176 else if (key == Qt::Key_Delete || key == Qt::Key_Escape)
1177 cancel_replacement =
true;
1178 else if (!
text.isEmpty ())
1180 else if (modifiers != Qt::ShiftModifier)
1181 cancel_replacement =
true;
1185 QsciScintilla::keyPressEvent (key_event);
1187 if (cancel_replacement)
1197 const QString&
line, QString& first_word)
1204 bool autofill_simple_end = (auto_endif == 2);
1206 size_t start =
line.toStdString ().find_first_not_of (
" \t");
1211 if (linenr < lines () - 1)
1220 next_line =
text (linenr + offset++);
1221 next_start = next_line.toStdString ().find_first_not_of (
" \t\n");
1223 while (linenr + offset < lines ()
1224 && next_start == std::string::npos);
1226 if (next_start == std::string::npos)
1228 if (start == 0 && next_start == 0)
1230 if (next_start > start)
1232 if (next_start == start)
1234 QRegExp rx_start = QRegExp (R
"((\w+))");
1235 int tmp = rx_start.indexIn (next_line, start);
1236 if (tmp != -1 &&
is_end (rx_start.cap(1), first_word))
1246 if (linenr + 2 == lines ())
1247 insertAt (QString (
"\n"), linenr + 2, 0);
1250 if (first_word ==
"try")
1251 insertAt (QString (start,
' ')
1252 + (autofill_simple_end ?
"end\n" :
"end_try_catch\n"),
1254 else if (first_word ==
"unwind_protect")
1255 insertAt (QString (start,
' ')
1256 + (autofill_simple_end ?
"end\n" :
"end_unwind_protect\n"),
1260 if (first_word ==
"do")
1261 next_line =
"until\n";
1262 else if (first_word ==
"try")
1263 next_line =
"catch\n";
1264 else if (first_word ==
"unwind_protect")
1265 next_line =
"unwind_protect_cleanup\n";
1266 else if (autofill_simple_end)
1267 next_line =
"end\n";
1270 if (first_word ==
"unwind_protect")
1271 first_word =
'_' + first_word;
1272 next_line =
"end" + first_word +
"\n";
1276 insertAt (next_line, linenr + 2, 0);
1277 setIndentation (linenr + 2, indentation (linenr));
1285 if (!e->mimeData ()->hasUrls ())
1287 QsciScintilla::dragEnterEvent (e);
Base class for Octave interfaces that use Qt.
resource_manager & get_resource_manager(void)
static void replace_line(const std::string &text, bool clear_undo=true)
static bool erase_empty_line(bool flag)
static void set_initial_input(const std::string &text)
static std::string get_current_line(void)
static void accept_line(void)
static void interrupt_event_loop(bool flag=true)
static void redisplay(void)
The documentation main class derived from QSplitter.
void source_file(const std::string &file_name, const std::string &context="", bool verbose=false, bool require_file=true)
void focus_console_after_command_signal(void)
void keyPressEvent(QKeyEvent *e)
void contextmenu_edit(bool)
void dragEnterEvent(QDragEnterEvent *e)
void contextmenu_help(bool)
void get_current_position(int *pos, int *line, int *col)
void interpreter_event(const meth_callback &meth)
void contextmenu_break_once(const QPoint &)
void ctx_menu_run_finished_signal(bool, int, QTemporaryFile *, QTemporaryFile *, bool, bool)
void contextmenu_help_doc(bool)
void smart_indent_line_or_selected_text(int lineFrom, int lineTo)
base_qobject & m_octave_qobj
octave_qscintilla(QWidget *p, base_qobject &oct_qobj)
void status_update(bool, bool)
void get_global_textcursor_pos(QPoint *global_pos, QPoint *local_pos)
void contextmenu_run(bool)
int get_style(int pos=-1)
void set_selection_marker_color(const QColor &c)
void auto_close(int auto_endif, int l, const QString &line, QString &first_word)
void show_replace_action_tooltip(void)
bool get_actual_word(void)
void show_doc_signal(const QString &)
void context_menu_break_once(int)
void smart_indent(bool do_smart_indent, int do_auto_close, int line, int ind_char_width)
virtual void contextMenuEvent(QContextMenuEvent *e)
void contextmenu_break_condition(bool)
void set_word_selection(const QString &word=QString())
QStringList comment_string(bool comment=true)
void cursor_position_changed(int, int)
void focusInEvent(QFocusEvent *focusEvent)
void context_menu_break_condition_signal(int)
void context_menu_edit_signal(const QString &)
void show_selection_markers(int l1, int c1, int l2, int c2)
void contextmenu_run_temp_error(void)
QString m_selection_replacement
void clear_selection_markers(void)
void contextmenu_doc(bool)
int is_style_comment(int pos=-1)
void create_context_menu_signal(QMenu *)
void context_help_doc(bool)
void ctx_menu_run_finished(bool, int, QTemporaryFile *, QTemporaryFile *, bool, bool)
void execute_command_in_terminal_signal(const QString &)
gui_settings * get_settings(void) const
QPointer< QTemporaryFile > create_tmp_file(const QString &extension=QString(), const QString &contents=QString())
void remove_tmp_file(QPointer< QTemporaryFile > tmp_file)
text(const graphics_handle &mh, const graphics_handle &p)
OCTAVE_EXPORT octave_value_list Fisdebugmode(octave::interpreter &interp, const octave_value_list &args, int)
const gui_pref ed_comment_str_old("editor/octave_comment_string", QVariant(0))
const gui_pref ed_uncomment_str("editor/oct_uncomment_str", QVariant(1+2+4+8))
const QStringList ed_comment_strings(QStringList()<< "##"<< "#"<< "%"<< "%%"<< "%!")
const gui_pref ed_show_dbg_file("editor/show_dbg_file", QVariant(true))
const gui_pref ed_comment_str("editor/oct_comment_str", QVariant(0))
const int ed_comment_strings_count
const Qt::KeyboardModifier CTRL
QString fromStdString(const std::string &s)
std::string toStdString(const QString &s)
static bool is_end(const QString &candidate, const QString &opening)
OCTAVE_EXPORT octave_value_list Fhistory(octave::interpreter &interp, const octave_value_list &args, int nargout)
octave_value::octave_value(const Array< char > &chm, char type) return retval
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.