GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
octave-qscintilla.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2013-2023 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #if defined (HAVE_QSCINTILLA)
31 
32 #include <Qsci/qscilexer.h>
33 
34 #include <QDir>
35 #include <QKeySequence>
36 #include <QMessageBox>
37 #include <QMimeData>
38 #include <QShortcut>
39 #include <QToolTip>
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>
47 #endif
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>
54 
55 #include "file-editor-tab.h"
56 #include "gui-preferences-ed.h"
57 // FIXME: hardwired marker numbers?
58 #include "marker.h"
59 #include "octave-qobject.h"
60 #include "octave-qscintilla.h"
61 #include "shortcut-manager.h"
62 #include "workspace-model.h"
63 
64 #include "builtin-defun-decls.h"
65 #include "cmd-edit.h"
66 #include "interpreter-private.h"
67 #include "interpreter.h"
68 
69 // Return true if CANDIDATE is a "closing" that matches OPENING,
70 // such as "end" or "endif" for "if", or "catch" for "try".
71 // Used for testing the last word of an "if" etc. line,
72 // or the first word of the following line.
73 
75 
76 static bool
77 is_end (const QString& candidate, const QString& opening)
78 {
79  bool retval = false;
80 
81  if (opening == "do") // The only one that can't be ended by "end"
82  {
83  if (candidate == "until")
84  retval = true;
85  }
86  else
87  {
88  if (candidate == "end")
89  retval = true;
90  else
91  {
92  if (opening == "try")
93  {
94  if (candidate == "catch" || candidate == "end_try_catch")
95  retval = true;
96  }
97  else if (opening == "unwind_protect")
98  {
99  if (candidate == "unwind_protect_cleanup"
100  || candidate == "end_unwind_protect")
101  retval = true;
102  }
103  else if (candidate == "end" + opening)
104  retval = true;
105  else if (opening == "if" && candidate == "else")
106  retval = true;
107  }
108  }
109 
110  return retval;
111 }
112 
114  : QsciScintilla (p), m_octave_qobj (oct_qobj), m_debug_mode (false),
115  m_word_at_cursor (), m_selection (), m_selection_replacement (),
116  m_selection_line (-1), m_selection_col (-1), m_indicator_id (1)
117 {
118  connect (this, SIGNAL (textChanged (void)),
119  this, SLOT (text_changed (void)));
120 
121  connect (this, SIGNAL (cursorPositionChanged (int, int)),
122  this, SLOT (cursor_position_changed (int, int)));
123 
126  Qt::QueuedConnection);
127 
128  // clear scintilla edit shortcuts that are handled by the editor
129  QsciCommandSet *cmd_set = standardCommands ();
130 
131  // Disable buffered drawing on all systems
132  SendScintilla (SCI_SETBUFFEREDDRAW, false);
133 
134 #if defined (HAVE_QSCI_VERSION_2_6_0)
135  // find () was added in QScintilla 2.6
136  cmd_set->find (QsciCommand::SelectionCopy)->setKey (0);
137  cmd_set->find (QsciCommand::SelectionCut)->setKey (0);
138  cmd_set->find (QsciCommand::Paste)->setKey (0);
139  cmd_set->find (QsciCommand::SelectAll)->setKey (0);
140  cmd_set->find (QsciCommand::SelectionDuplicate)->setKey (0);
141  cmd_set->find (QsciCommand::LineTranspose)->setKey (0);
142  cmd_set->find (QsciCommand::Undo)->setKey (0);
143  cmd_set->find (QsciCommand::Redo)->setKey (0);
144  cmd_set->find (QsciCommand::SelectionUpperCase)->setKey (0);
145  cmd_set->find (QsciCommand::SelectionLowerCase)->setKey (0);
146  cmd_set->find (QsciCommand::ZoomIn)->setKey (0);
147  cmd_set->find (QsciCommand::ZoomOut)->setKey (0);
148  cmd_set->find (QsciCommand::DeleteWordLeft)->setKey (0);
149  cmd_set->find (QsciCommand::DeleteWordRight)->setKey (0);
150  cmd_set->find (QsciCommand::DeleteLineLeft)->setKey (0);
151  cmd_set->find (QsciCommand::DeleteLineRight)->setKey (0);
152  cmd_set->find (QsciCommand::LineDelete)->setKey (0);
153  cmd_set->find (QsciCommand::LineCut)->setKey (0);
154  cmd_set->find (QsciCommand::LineCopy)->setKey (0);
155 #else
156  // find commands via its default key (tricky way without find ())
157  QList< QsciCommand * > cmd_list = cmd_set->commands ();
158  for (int i = 0; i < cmd_list.length (); i++)
159  {
160  int cmd_key = cmd_list.at (i)->key ();
161  switch (cmd_key)
162  {
163  case Qt::Key_C | Qt::CTRL : // SelectionCopy
164  case Qt::Key_X | Qt::CTRL : // SelectionCut
165  case Qt::Key_V | Qt::CTRL : // Paste
166  case Qt::Key_A | Qt::CTRL : // SelectAll
167  case Qt::Key_D | Qt::CTRL : // SelectionDuplicate
168  case Qt::Key_T | Qt::CTRL : // LineTranspose
169  case Qt::Key_Z | Qt::CTRL : // Undo
170  case Qt::Key_Y | Qt::CTRL : // Redo
171  case Qt::Key_Z | Qt::CTRL | Qt::SHIFT : // Redo
172  case Qt::Key_U | Qt::CTRL : // SelectionLowerCase
173  case Qt::Key_U | Qt::CTRL | Qt::SHIFT : // SelectionUpperCase
174  case Qt::Key_Plus | Qt::CTRL : // ZoomIn
175  case Qt::Key_Minus | Qt::CTRL : // ZoomOut
176  case Qt::Key_Backspace | Qt::CTRL | Qt::SHIFT : // DeleteLineLeft
177  case Qt::Key_Delete | Qt::CTRL | Qt::SHIFT : // DeleteLineRight
178  case Qt::Key_K | Qt::META : // DeleteLineRight
179  case Qt::Key_Backspace | Qt::CTRL : // DeleteWordLeft
180  case Qt::Key_Delete | Qt::CTRL : // DeleteWordRight
181  case Qt::Key_L | Qt::CTRL | Qt::SHIFT : // LineDelete
182  case Qt::Key_L | Qt::CTRL : // LineCut
183  case Qt::Key_T | Qt::CTRL | Qt::SHIFT : // LineCopy
184  cmd_list.at (i)->setKey (0);
185  }
186  }
187 #endif
188 
189 #if defined (Q_OS_MAC)
190  // Octave interprets Cmd key as Meta whereas Qscintilla interprets it
191  // as Ctrl. We thus invert Meta/Ctrl in Qscintilla's shortcuts list.
192  QList< QsciCommand * > cmd_list_mac = cmd_set->commands ();
193  for (int i = 0; i < cmd_list_mac.length (); i++)
194  {
195  // Primary key
196  int key = cmd_list_mac.at (i)->key ();
197 
198  if (static_cast<int> (key | Qt::META) == key
199  && static_cast<int> (key | Qt::CTRL) != key)
200  key = (key ^ Qt::META) | Qt::CTRL;
201  else if (static_cast<int> (key | Qt::CTRL) == key)
202  key = (key ^ Qt::CTRL) | Qt::META;
203 
204  cmd_list_mac.at (i)->setKey (key);
205 
206  // Alternate key
207  key = cmd_list_mac.at (i)->alternateKey ();
208 
209  if (static_cast<int> (key | Qt::META) == key
210  && static_cast<int> (key | Qt::CTRL) != key)
211  key = (key ^ Qt::META) | Qt::CTRL;
212  else if (static_cast<int> (key | Qt::CTRL) == key)
213  key = (key ^ Qt::CTRL) | Qt::META;
214 
215  cmd_list_mac.at (i)->setAlternateKey (key);
216  }
217 #endif
218 
219  // selection markers
220 
221  m_indicator_id = indicatorDefine (QsciScintilla::StraightBoxIndicator);
222  if (m_indicator_id == -1)
223  m_indicator_id = 1;
224 
225  setIndicatorDrawUnder (true, m_indicator_id);
226 
227  markerDefine (QsciScintilla::Minus, marker::selection);
228 
229  // init state of undo/redo action for this tab
230  emit status_update (isUndoAvailable (), isRedoAvailable ());
231 }
232 
233 void octave_qscintilla::setCursorPosition (int line, int col)
234 {
235  QsciScintilla::setCursorPosition (line, col);
236  emit update_rowcol_indicator_signal (line, col);
237 }
238 
240 {
241  QColor ic = c;
242  ic.setAlphaF (0.45);
243  setIndicatorForegroundColor (ic, m_indicator_id);
244  setIndicatorOutlineColor (ic, m_indicator_id);
245 
246  setMarkerForegroundColor (c, marker::selection);
247  setMarkerBackgroundColor (c, marker::selection);
248 }
249 
250 // context menu requested
251 void octave_qscintilla::contextMenuEvent (QContextMenuEvent *e)
252 {
253 #if defined (HAVE_QSCI_VERSION_2_6_0)
254  QPoint global_pos, local_pos; // the menu's position
255  QMenu *context_menu = createStandardContextMenu (); // standard menu
256 
257  bool in_left_margin = false;
258 
259  // determine position depending on mouse or keyboard event
260  if (e->reason () == QContextMenuEvent::Mouse)
261  {
262  // context menu by mouse
263  global_pos = e->globalPos (); // global mouse position
264  local_pos = e->pos (); // local mouse position
265  if (e->x () < marginWidth (1) + marginWidth (2))
266  in_left_margin = true;
267  }
268  else
269  {
270  // context menu by keyboard or other: get point of text cursor
271  get_global_textcursor_pos (&global_pos, &local_pos);
272  QRect editor_rect = geometry (); // editor rect mapped to global
273  editor_rect.moveTopLeft
274  (parentWidget ()->mapToGlobal (editor_rect.topLeft ()));
275  if (! editor_rect.contains (global_pos)) // is cursor outside editor?
276  global_pos = editor_rect.topLeft (); // yes, take top left corner
277  }
278 
279 # if defined (HAVE_QSCI_VERSION_2_6_0)
280  if (! in_left_margin)
281 # endif
282  {
283  // fill context menu with editor's standard actions
284  emit create_context_menu_signal (context_menu);
285 
286  // additional custom entries of the context menu
287  context_menu->addSeparator (); // separator before custom entries
288 
289  // help menu: get the position of the mouse or the text cursor
290  // (only for octave files)
291  QString lexer_name = lexer ()->lexer ();
292  if (lexer_name == "octave" || lexer_name == "matlab")
293  {
294  m_word_at_cursor = wordAtPoint (local_pos);
295  if (! m_word_at_cursor.isEmpty ())
296  {
297  context_menu->addAction (tr ("Help on") + ' ' + m_word_at_cursor,
299  context_menu->addAction (tr ("Documentation on")
300  + ' ' + m_word_at_cursor,
302  context_menu->addAction (tr ("Edit") + ' ' + m_word_at_cursor,
304  }
305  }
306  }
307 # if defined (HAVE_QSCI_VERSION_2_6_0)
308  else
309  {
310  // remove all standard actions from scintilla
311  QList<QAction *> all_actions = context_menu->actions ();
312 
313  for (auto *a : all_actions)
314  context_menu->removeAction (a);
315 
316  QAction *act
317  = context_menu->addAction (tr ("dbstop if ..."), this,
319  act->setData (local_pos);
320  }
321 # endif
322 
323  // finally show the menu
324  context_menu->exec (global_pos);
325 
326 #else
327 
328  octave_unused_parameter (e);
329 
330 #endif
331 }
332 
333 // common function with flag for documentation
335 {
336  if (documentation)
338  else
340 }
341 
342 // call edit the function related to the current word
344 {
345  if (get_actual_word ())
346  contextmenu_edit (true);
347 }
348 
349 // call edit the function related to the current word
351 {
352  if (hasSelectedText ())
353  {
354  contextmenu_run (true);
355 
356  emit interpreter_event
357  ([] (interpreter&)
358  { command_editor::erase_empty_line (false); });
359  }
360 }
361 
363  QPoint *local_pos)
364 {
365  long position = SendScintilla (SCI_GETCURRENTPOS);
366  long point_x = SendScintilla (SCI_POINTXFROMPOSITION, 0, position);
367  long point_y = SendScintilla (SCI_POINTYFROMPOSITION, 0, position);
368  *local_pos = QPoint (point_x, point_y); // local cursor position
369  *global_pos = mapToGlobal (*local_pos); // global position of cursor
370 }
371 
372 // determine the actual word and whether we are in an octave or matlab script
374 {
375  QPoint global_pos, local_pos;
376  get_global_textcursor_pos (&global_pos, &local_pos);
377  m_word_at_cursor = wordAtPoint (local_pos);
378  QString lexer_name = lexer ()->lexer ();
379  return ((lexer_name == "octave" || lexer_name == "matlab")
380  && ! m_word_at_cursor.isEmpty ());
381 }
382 
383 // helper function for clearing all indicators of a specific style
385 {
386  int end_pos = text ().length ();
387  int end_line, end_col;
388  lineIndexFromPosition (end_pos, &end_line, &end_col);
389  clearIndicatorRange (0, 0, end_line, end_col, m_indicator_id);
390 
391  markerDeleteAll (marker::selection);
392 }
393 
395 {
396  switch (eolMode ())
397  {
398  case QsciScintilla::EolWindows:
399  return ("\r\n");
400  case QsciScintilla::EolMac:
401  return ("\r");
402  case QsciScintilla::EolUnix:
403  return ("\n");
404  }
405 
406  // Last resort, if the above goes wrong (should never happen)
407  return ("\r\n");
408 }
409 
410 // Function returning the true cursor position where the tab length
411 // is taken into account.
412 void octave_qscintilla::get_current_position (int *pos, int *line, int *col)
413 {
414  *pos = SendScintilla (QsciScintillaBase::SCI_GETCURRENTPOS);
415  *line = SendScintilla (QsciScintillaBase::SCI_LINEFROMPOSITION, *pos);
416  *col = SendScintilla (QsciScintillaBase::SCI_GETCOLUMN, *pos);
417 }
418 
419 // Function returning the comment string of the current lexer
420 QStringList octave_qscintilla::comment_string (bool comment)
421 {
422  int lexer = SendScintilla (SCI_GETLEXER);
423 
424  switch (lexer)
425  {
426 #if defined (HAVE_LEXER_OCTAVE) || defined (HAVE_LEXER_MATLAB)
427 #if defined (HAVE_LEXER_OCTAVE)
428  case SCLEX_OCTAVE:
429 #else
430  case SCLEX_MATLAB:
431 #endif
432  {
435  int comment_string;
436 
437  if (comment)
438  {
439  // The commenting string is requested
440  if (settings->contains (ed_comment_str.key))
441  // new version (radio buttons)
442  comment_string = settings->value (ed_comment_str).toInt ();
443  else
444  // old version (combo box)
446  ed_comment_str.def).toInt ();
447 
448  return (QStringList (ed_comment_strings.at (comment_string)));
449  }
450  else
451  {
452  QStringList c_str;
453 
454  // The possible uncommenting string(s) are requested
455  comment_string = settings->value (ed_uncomment_str).toInt ();
456 
457  for (int i = 0; i < ed_comment_strings_count; i++)
458  {
459  if (1 << i & comment_string)
460  c_str.append (ed_comment_strings.at (i));
461  }
462 
463  return c_str;
464  }
465 
466  }
467 #endif
468 
469  case SCLEX_PERL:
470  case SCLEX_BASH:
471  case SCLEX_DIFF:
472  return QStringList ("#");
473 
474  case SCLEX_CPP:
475  return QStringList ("//");
476 
477  case SCLEX_BATCH:
478  return QStringList ("REM ");
479  }
480 
481  return QStringList ("%"); // should never happen
482 }
483 
484 // provide the style at a specific position
486 {
487  int position;
488  if (pos < 0)
489  // The positition has to be reduced by 2 for getting the real style (?)
490  position = SendScintilla (QsciScintillaBase::SCI_GETCURRENTPOS) - 2;
491  else
492  position = pos;
493 
494  return SendScintilla (QsciScintillaBase::SCI_GETSTYLEAT, position);
495 }
496 
497 // Is a specific cursor position in a line or block comment?
499 {
500  int lexer = SendScintilla (QsciScintillaBase::SCI_GETLEXER);
501  int style = get_style (pos);
502 
503  switch (lexer)
504  {
505  case SCLEX_CPP:
506  return (ST_LINE_COMMENT * (style == QsciLexerCPP::CommentLine
507  || style == QsciLexerCPP::CommentLineDoc)
508  + ST_BLOCK_COMMENT * (style == QsciLexerCPP::Comment
509  || style == QsciLexerCPP::CommentDoc
510  || style == QsciLexerCPP::CommentDocKeyword
511  || style == QsciLexerCPP::CommentDocKeywordError));
512 
513 #if defined (HAVE_LEXER_MATLAB)
514  case SCLEX_MATLAB:
515  return (ST_LINE_COMMENT * (style == QsciLexerMatlab::Comment));
516 #endif
517 #if defined (HAVE_LEXER_OCTAVE)
518  case SCLEX_OCTAVE:
519  return (ST_LINE_COMMENT * (style == QsciLexerOctave::Comment));
520 #endif
521 
522  case SCLEX_PERL:
523  return (ST_LINE_COMMENT * (style == QsciLexerPerl::Comment));
524 
525  case SCLEX_BATCH:
526  return (ST_LINE_COMMENT * (style == QsciLexerBatch::Comment));
527 
528  case SCLEX_DIFF:
529  return (ST_LINE_COMMENT * (style == QsciLexerDiff::Comment));
530 
531  case SCLEX_BASH:
532  return (ST_LINE_COMMENT * (style == QsciLexerBash::Comment));
533 
534  }
535 
536  return ST_NONE;
537 }
538 
539 // Do smart indentation after if, for, ...
540 void octave_qscintilla::smart_indent (bool do_smart_indent, int do_auto_close,
541  int line, int ind_char_width)
542 {
543  QString prevline = text (line);
544 
545  QRegExp bkey = QRegExp ("^[\t ]*(if|for|while|switch"
546  "|do|function|properties|events|classdef"
547  "|unwind_protect|try"
548  "|parfor|methods)"
549  "[\r]?[\n\t #%]");
550  // last word except for comments, assuming no ' or " in comment.
551  // rx_end = QRegExp ("(\\w+)[ \t;\r\n]*([%#][^\"']*)?$");
552 
553  // last word except for comments,
554  // allowing % and # in single or double quoted strings
555  // FIXME: This will get confused by transpose.
556  QRegExp ekey = QRegExp ("(?:(?:['\"][^'\"]*['\"])?[^%#]*)*"
557  "(\\w+)[ \t;\r\n]*(?:[%#].*)?$");
558 
559  int bpos = bkey.indexIn (prevline, 0);
560  int epos;
561 
562  if (bpos > -1)
563  {
564  // Found keyword after that indentation should be added
565 
566  // Check for existing end statement in the same line
567  epos = ekey.indexIn (prevline, bpos);
568  QString first_word = bkey.cap(1);
569  bool inline_end = (epos > -1) && is_end (ekey.cap(1), first_word);
570 
571  if (do_smart_indent && ! inline_end)
572  {
573  // Do smart indent in the current line (line+1)
574  indent (line+1);
575  setCursorPosition (line+1, indentation (line+1) / ind_char_width);
576  }
577 
578  if (do_auto_close
579  && ! inline_end
580  && ! first_word.contains (QRegExp ("(?:case|otherwise|unwind_protect_cleanup)")))
581  {
582  // Do auto close
583  auto_close (do_auto_close, line, prevline, first_word);
584  }
585 
586  return;
587  }
588 
589  QRegExp mkey = QRegExp ("^[\t ]*(?:else|elseif|catch|unwind_protect_cleanup)"
590  "[\r]?[\t #%\n]");
591  if (prevline.contains (mkey))
592  {
593  int prev_ind = indentation (line-1);
594  int act_ind = indentation (line);
595 
596  if (prev_ind == act_ind)
597  unindent (line);
598  else if (prev_ind > act_ind)
599  {
600  setIndentation (line+1, prev_ind);
601  setCursorPosition (line+1, prev_ind);
602  }
603  return;
604  }
605 
606  QRegExp case_key = QRegExp ("^[\t ]*(?:case|otherwise)[\r]?[\t #%\n]");
607  if (prevline.contains (case_key) && do_smart_indent)
608  {
609  QString last_line = text (line-1);
610  int prev_ind = indentation (line-1);
611  int act_ind = indentation (line);
612 
613  if (last_line.contains (QRegExp ("^[\t ]*switch")))
614  {
615  indent (line+1);
616  act_ind = indentation (line+1);
617  }
618  else
619  {
620  if (prev_ind == act_ind)
621  unindent (line);
622  else if (prev_ind > act_ind)
623  act_ind = prev_ind;
624  }
625 
626  setIndentation (line+1, act_ind);
627  setCursorPosition (line+1, act_ind);
628  }
629 
630  ekey = QRegExp ("^[\t ]*(?:end|endif|endfor|endwhile|until|endfunction"
631  "|endswitch|end_try_catch|end_unwind_protect)[\r]?[\t #%\n(;]");
632  if (prevline.contains (ekey))
633  {
634  if (indentation (line-1) <= indentation (line))
635  {
636  unindent (line+1);
637  unindent (line);
638  if (prevline.contains ("endswitch"))
639  {
640  // endswitch has to me unndented twice
641  unindent (line+1);
642  unindent (line);
643  }
644  setCursorPosition (line+1,
645  indentation (line));
646  }
647  return;
648  }
649 }
650 
651 // Do smart indentation of current selection or line.
653  int lineTo)
654 {
655  QRegExp blank_line_regexp = QRegExp ("^[\t ]*$");
656 
657  // end[xxxxx] [# comment] at end of a line
658  QRegExp end_word_regexp
659  = QRegExp ("(?:(?:['\"][^'\"]*['\"])?[^%#]*)*"
660  "(?:end\\w*)[\r\n\t ;]*(?:[%#].*)?$");
661 
662  QRegExp begin_block_regexp
663  = QRegExp ("^[\t ]*(?:if|elseif|else"
664  "|for|while|do|parfor"
665  "|switch|case|otherwise"
666  "|function"
667  "|classdef|properties|events|enumeration|methods"
668  "|unwind_protect|unwind_protect_cleanup|try|catch)"
669  "[\r\n\t #%]");
670 
671  QRegExp mid_block_regexp
672  = QRegExp ("^[\t ]*(?:elseif|else"
673  "|unwind_protect_cleanup|catch)"
674  "[\r\n\t #%]");
675 
676  QRegExp end_block_regexp
677  = QRegExp ("^[\t ]*(?:end"
678  "|end(for|function|if|parfor|switch|while"
679  "|classdef|enumeration|events|methods|properties)"
680  "|end_(try_catch|unwind_protect)"
681  "|until)"
682  "[\r\n\t #%]");
683 
684  QRegExp case_block_regexp
685  = QRegExp ("^[\t ]*(?:case|otherwise)"
686  "[\r\n\t #%]");
687 
688  int indent_column = -1;
689  int indent_increment = indentationWidth ();
690  bool in_switch = false;
691 
692  for (int line = lineFrom-1; line >= 0; line--)
693  {
694  QString line_text = text (line);
695 
696  if (blank_line_regexp.indexIn (line_text) < 0)
697  {
698  // Found first non-blank line above beginning of region or
699  // current line. Base indentation from this line, increasing
700  // indentation by indentationWidth if it looks like the
701  // beginning of a code block.
702 
703  indent_column = indentation (line);
704 
705  if (begin_block_regexp.indexIn (line_text) > -1)
706  {
707  indent_column += indent_increment;
708  if (line_text.contains ("switch"))
709  in_switch = true;
710  }
711 
712  break;
713  }
714  }
715 
716  if (indent_column < 0)
717  indent_column = indentation (lineFrom);
718 
719  QString prev_line;
720  for (int line = lineFrom; line <= lineTo; line++)
721  {
722  QString line_text = text (line);
723 
724  if (end_block_regexp.indexIn (line_text) > -1)
725  {
726  indent_column -= indent_increment;
727  if (line_text.contains ("endswitch"))
728  {
729  // need a double de-indent for endswitch
730  if (in_switch)
731  indent_column -= indent_increment;
732  in_switch = false;
733  }
734  }
735 
736  if (mid_block_regexp.indexIn (line_text) > -1)
737  indent_column -= indent_increment;
738 
739  if (case_block_regexp.indexIn (line_text) > -1)
740  {
741  if (case_block_regexp.indexIn (prev_line) < 0
742  && !prev_line.contains("switch"))
743  indent_column -= indent_increment;
744  in_switch = true;
745  }
746 
747  setIndentation (line, indent_column);
748 
749  int bpos = begin_block_regexp.indexIn (line_text);
750  if (bpos > -1)
751  {
752  // Check for existing end statement in the same line
753  int epos = end_word_regexp.indexIn (line_text, bpos);
754  if (epos == -1)
755  indent_column += indent_increment;
756  if (line_text.contains ("switch"))
757  in_switch = true;
758  }
759 
760  if (blank_line_regexp.indexIn (line_text) < 0)
761  prev_line = line_text;
762  }
763 }
764 
765 void octave_qscintilla::set_word_selection (const QString& word)
766 {
767  m_selection = word;
768 
769  if (word.isEmpty ())
770  {
771  m_selection_line = -1;
772  m_selection_col = -1;
773 
775 
777 
778  QToolTip::hideText ();
779  }
780  else
781  {
782  int pos;
784  }
785 }
786 
787 void octave_qscintilla::show_selection_markers (int l1, int c1, int l2, int c2)
788 {
789  fillIndicatorRange (l1, c1, l2, c2, m_indicator_id);
790 
791  if (l1 == l2)
792  markerAdd (l1, marker::selection);
793 }
794 
796 {
797  contextmenu_help_doc (false);
798 }
799 
801 {
802  contextmenu_help_doc (true);
803 }
804 
806 {
807  if (get_actual_word ())
809 }
810 
812 {
814 }
815 
817 {
818  QMessageBox::critical (this, tr ("Octave Editor"),
819  tr ("Creating temporary files failed.\n"
820  "Make sure you have write access to temp. directory\n"
821  "%1\n\n"
822  "\"Run Selection\" requires temporary files.").arg (QDir::tempPath ()));
823 }
824 
826 {
828 
829  // Take selected code and extend it by commands for echoing each
830  // evaluated line and for adding the line to the history (use script)
831  QString code = QString ();
832  QString hist = QString ();
833 
834  // Split contents into single lines and complete commands
835  QStringList lines = selectedText ().split (QRegExp ("[\r\n]"),
836 #if defined (HAVE_QT_SPLITBEHAVIOR_ENUM)
837  Qt::SkipEmptyParts);
838 #else
839  QString::SkipEmptyParts);
840 #endif
841 for (int i = 0; i < lines.count (); i++)
842  {
843  QString line = lines.at (i);
844  if (line.trimmed ().isEmpty ())
845  continue;
846  QString line_escaped = line;
847  line_escaped.replace (QString ("'"), QString ("''"));
848  QString line_history = line;
849 
850  // Prevent output of breakpoint in temp. file for keyboard
851  QString next_bp_quiet;
852  QString next_bp_quiet_reset;
853  if (line.contains ("keyboard"))
854  {
855  // Define commands for not showing bp location and for resetting
856  // this in case "keyboard" was within a comment
857  next_bp_quiet = "__db_next_breakpoint_quiet__;\n";
858  next_bp_quiet_reset = "\n__db_next_breakpoint_quiet__(false);";
859  }
860 
861  // Add codeline
862  code += next_bp_quiet + line + next_bp_quiet_reset + "\n";
863  hist += line_history + "\n";
864  }
865 
866 octave_stdout << hist.toStdString ();
867 
868 // Create tmp file with the code to be executed by the interpreter
869 QPointer<QTemporaryFile> tmp_file
870 = rmgr.create_tmp_file ("m", code);
871 
872 bool tmp = (tmp_file && tmp_file->open ());
873 if (! tmp)
874  {
875  // tmp files not working: use old way to run selection
877  return;
878  }
879 
880 tmp_file->close ();
881 
882 // Create tmp file required for adding command to history
883 QPointer<QTemporaryFile> tmp_hist
884 = rmgr.create_tmp_file ("", hist); // empty tmp file for history
885 
886 tmp = (tmp_hist && tmp_hist->open ());
887 if (! tmp)
888  {
889  // tmp files not working: use old way to run selection
891  return;
892  }
893 
894 tmp_hist->close ();
895 
896 // Add commands to the history
898 ([=] (interpreter& interp)
899  {
900  // INTERPRETER THREAD
901 
902  if (tmp_hist.isNull ())
903  return;
904 
905  std::string opt = "-r";
906  std::string path = tmp_hist->fileName ().toStdString ();
907 
908  Fhistory (interp, ovl (opt, path));
909  });
910 
911 // Disable opening a file at a breakpoint in case keyboard () is used
913 bool show_dbg_file = settings->value (ed_show_dbg_file).toBool ();
914 settings->setValue (ed_show_dbg_file.key, false);
915 
916 // The interpreter_event callback function below emits a signal.
917 // Because we don't control when that happens, use a guarded pointer
918 // so that the callback can abort if this object is no longer valid.
919 
920 QPointer<octave_qscintilla> this_oq (this);
921 
922 // Let the interpreter execute the tmp file
924 ([=] (interpreter& interp)
925  {
926  // INTERPRETER THREAD
927 
928  // FIXME: For now, just skip the entire callback if THIS_OQ is no
929  // longer valid. Maybe there is a better way to do this job?
930 
931  if (this_oq.isNull ())
932  return;
933 
934  std::string file = tmp_file->fileName ().toStdString ();
935 
936  std::string pending_input = command_editor::get_current_line ();
937 
938  int err_line = -1; // For storing the line of a poss. error
939 
940  // Get current state of auto command repeat in debug mode
941  octave_value_list ovl_dbg = Fisdebugmode (interp);
942  bool dbg = ovl_dbg(0).bool_value ();
943  octave_value_list ovl_auto_repeat = ovl (true);
944  if (dbg)
945  ovl_auto_repeat = Fauto_repeat_debug_command (interp, ovl (false), 1);
946  bool auto_repeat = ovl_auto_repeat(0).bool_value ();
947 
948  try
949  {
950  // Do the job
951  interp.source_file (file);
952  }
953  catch (const execution_exception& ee)
954  {
955  // Catch errors otherwise the rest of the interpreter
956  // will not be executed (cleaning up).
957 
958  // New error message and error stack
959  QString new_msg = QString::fromStdString (ee.message ());
960  std::list<frame_info> stack = ee.stack_info ();
961 
962  // Remove line and column from first line of error message only
963  // if it is related to the tmp itself, i.e. only if the
964  // the error stack size is 0, 1, or, if in debug mode, 2
965  size_t max_stack_size = 1;
966  if (dbg)
967  max_stack_size = 2;
968  if (stack.size () <= max_stack_size)
969  {
970  QRegExp rx ("source: error sourcing file [^\n]*$");
971  if (new_msg.contains (rx))
972  {
973  // Selected code has syntax errors
974  new_msg.replace (rx, "error sourcing selected code");
975  err_line = 0; // Nothing into history?
976  }
977  else
978  {
979  // Normal error, detect line and remove file
980  // name from message
981  QStringList rx_list;
982  rx_list << "near line (\\d+),[^\n]*\n";
983  rx_list << "near line (\\d+),[^\n]*$";
984 
985  QStringList replace_list;
986  replace_list << "\n";
987  replace_list << "";
988 
989  for (int i = 0; i < rx_list.length (); i++)
990  {
991  int pos = 0;
992  rx = QRegExp (rx_list.at (i));
993  pos = rx.indexIn (new_msg, pos);
994  if (pos != -1)
995  {
996  err_line = rx.cap (1).toInt ();
997  new_msg = new_msg.replace (rx, replace_list.at (i));
998  }
999  }
1000  }
1001  }
1002 
1003  // Drop first stack level, which is the temporary function file,
1004  // or, if in debug mode, drop first two stack levels
1005  if (stack.size () > 0)
1006  stack.pop_back ();
1007  if (dbg && (stack.size () > 0))
1008  stack.pop_back ();
1009 
1010  // Clean up before throwing the modified error.
1011  emit ctx_menu_run_finished_signal (show_dbg_file, err_line,
1012  tmp_file, tmp_hist,
1013  dbg, auto_repeat);
1014 
1015  // New exception with updated message and stack
1016  execution_exception nee (ee.err_type (), ee.identifier (),
1017  new_msg.toStdString (), stack);
1018 
1019  // Throw
1020  throw (nee);
1021  }
1022 
1023  // Clean up
1024 
1025  emit ctx_menu_run_finished_signal (show_dbg_file, err_line,
1026  tmp_file, tmp_hist,
1027  dbg, auto_repeat);
1028 
1031  command_editor::set_initial_input (pending_input);
1036 
1037  });
1038 }
1039 
1040 void octave_qscintilla::ctx_menu_run_finished (bool show_dbg_file, int,
1041  QTemporaryFile* tmp_file, QTemporaryFile* tmp_hist,
1042  bool dbg, bool auto_repeat)
1043 {
1045 
1046  // TODO: Use line nr. (int argument) of possible error for removing
1047  // lines from history that were never executed. For this,
1048  // possible lines from commands at a debug prompt must be
1049  // taken into consideration.
1051  gui_settings *settings = rmgr.get_settings ();
1052  settings->setValue (ed_show_dbg_file.key, show_dbg_file);
1053  rmgr.remove_tmp_file (tmp_file);
1054  rmgr.remove_tmp_file (tmp_hist);
1055 
1056  emit interpreter_event
1057  ([=] (interpreter& interp)
1058  {
1059  // INTERPRETER THREAD
1060  if (dbg)
1061  Fauto_repeat_debug_command (interp, ovl (auto_repeat));
1062  });
1063 }
1064 
1065 // wrappers for dbstop related context menu items
1066 
1067 // FIXME: Why can't the data be sent as the argument to the function???
1069 {
1070 #if defined (HAVE_QSCI_VERSION_2_6_0)
1071  QAction *action = qobject_cast<QAction *>(sender ());
1072  QPoint local_pos = action->data ().value<QPoint> ();
1073 
1074  // pick point just right of margins, so lineAt doesn't give -1
1075  int margins = marginWidth (1) + marginWidth (2) + marginWidth (3);
1076  local_pos = QPoint (margins + 1, local_pos.y ());
1077 
1078  emit context_menu_break_condition_signal (lineAt (local_pos));
1079 #endif
1080 }
1081 
1082 void octave_qscintilla::contextmenu_break_once (const QPoint& local_pos)
1083 {
1084 #if defined (HAVE_QSCI_VERSION_2_6_0)
1085  emit context_menu_break_once (lineAt (local_pos));
1086 #else
1087  octave_unused_parameter (local_pos);
1088 #endif
1089 }
1090 
1092 {
1093  emit status_update (isUndoAvailable (), isRedoAvailable ());
1094 }
1095 
1097 {
1098  // Clear the selection if we move away from it. We have to check the
1099  // position, because we allow entering text at the point of the
1100  // selection to trigger a search and replace that does not clear the
1101  // selection until it is complete.
1102 
1103  if (! m_selection.isEmpty ()
1104  && (line != m_selection_line || col != m_selection_col))
1105  set_word_selection ();
1106 }
1107 
1108 // when edit area gets focus update information on undo/redo actions
1109 void octave_qscintilla::focusInEvent (QFocusEvent *focusEvent)
1110 {
1111  emit status_update (isUndoAvailable (), isRedoAvailable ());
1112 
1113  QsciScintilla::focusInEvent (focusEvent);
1114 }
1115 
1117 {
1118  int pos;
1120 
1121  // Offer to replace other instances.
1122 
1123  QKeySequence keyseq = Qt::SHIFT + Qt::Key_Return;
1124 
1125  QString msg = (tr ("Press '%1' to replace all occurrences of '%2' with '%3'.")
1126  . arg (keyseq.toString ())
1127  . arg (m_selection)
1128  . arg (m_selection_replacement));
1129 
1130  QPoint global_pos;
1131  QPoint local_pos;
1132 
1133  get_global_textcursor_pos (&global_pos, &local_pos);
1134 
1135  QFontMetrics ttfm (QToolTip::font ());
1136 
1137  // Try to avoid overlapping with the text completion dialog
1138  // and the text that is currently being edited.
1139 
1140  global_pos += QPoint (2*ttfm.maxWidth (), -3*ttfm.height ());
1141 
1142  QToolTip::showText (global_pos, msg);
1143 }
1144 
1145 void octave_qscintilla::replace_all (const QString& o_str, const QString& n_str,
1146  bool re, bool cs, bool wo)
1147 {
1148  // get the resulting cursor position
1149  int pos, line, col, nline, ncol;
1150  get_current_position (&pos, &line, &col);
1151 
1152  // remember first visible line for restoring the view afterwards
1153  int first_line = firstVisibleLine ();
1154 
1155  // search for first occurrence of the detected word
1156  bool find_result_available = findFirst (o_str, re, cs, wo,
1157  false, true, 0, 0);
1158  // replace and find more occurrences in a loop
1159  beginUndoAction ();
1160  while (find_result_available)
1161  {
1162  // findNext doesn't work properly if the length of the replacement
1163  // text is different from the original
1164  replace (n_str);
1165  get_current_position (&pos, &nline, &ncol);
1166 
1167  find_result_available = findFirst (o_str, re, cs, wo,
1168  false, true, nline, ncol);
1169  }
1170  endUndoAction ();
1171 
1172  // restore the visible area
1173  setFirstVisibleLine (first_line);
1174 
1175  // fix cursor column if outside of new line length
1176  int eol_len = eol_string ().length ();
1177  if (line == lines () - 1)
1178  eol_len = 0;
1179  const int col_max = text (line).length () - eol_len;
1180  if (col_max < col)
1181  col = col_max;
1182 
1183  setCursorPosition (line, col);
1184 }
1185 
1187 {
1188  if (m_debug_mode && e->type() == QEvent::ToolTip)
1189  {
1190  QHelpEvent *help_e = static_cast<QHelpEvent *>(e);
1191  QString variable = wordAtPoint (help_e->pos());
1192  QStringList symbol_names
1194  int symbol_idx = symbol_names.indexOf (variable);
1195  if (symbol_idx > -1)
1196  {
1197  QStringList symbol_values
1199  QToolTip::showText (help_e->globalPos(), variable
1200  + " = " + symbol_values.at (symbol_idx));
1201  }
1202  else
1203  {
1204  QToolTip::hideText();
1205  e->ignore();
1206  }
1207 
1208  return true;
1209  }
1210 
1211  return QsciScintilla::event(e);
1212 }
1213 
1214 void octave_qscintilla::keyPressEvent (QKeyEvent *key_event)
1215 {
1216  if (m_selection.isEmpty ())
1217  QsciScintilla::keyPressEvent (key_event);
1218  else
1219  {
1220  int key = key_event->key ();
1221  Qt::KeyboardModifiers modifiers = key_event->modifiers ();
1222 
1223  if (key == Qt::Key_Return && modifiers == Qt::ShiftModifier)
1224  {
1226  false, true, true);
1227 
1228  // Clear the selection.
1229  set_word_selection ();
1230  }
1231  else
1232  {
1233  // The idea here is to allow backspace to remove the last
1234  // character of the replacement text to allow minimal editing
1235  // and to also end the selection replacement action if text is
1236  // not valid as a word constituent (control characters,
1237  // etc.). Is there a better way than having special cases for
1238  // DEL and ESC here?
1239 
1240  QString text = key_event->text ();
1241 
1242  bool cancel_replacement = false;
1243 
1244  if (key == Qt::Key_Backspace)
1245  {
1246  if (m_selection_replacement.isEmpty ())
1247  cancel_replacement = true;
1248  else
1249  m_selection_replacement.chop (1);
1250  }
1251  else if (key == Qt::Key_Delete || key == Qt::Key_Escape)
1252  cancel_replacement = true;
1253  else if (! text.isEmpty ())
1254  m_selection_replacement += text;
1255  else if (modifiers != Qt::ShiftModifier)
1256  cancel_replacement = true;
1257 
1258  // Perform default action.
1259 
1260  QsciScintilla::keyPressEvent (key_event);
1261 
1262  if (cancel_replacement)
1263  set_word_selection ();
1264 
1265  if (! m_selection_replacement.isEmpty ())
1267  }
1268  }
1269 }
1270 
1271 void octave_qscintilla::auto_close (int auto_endif, int linenr,
1272  const QString& line, QString& first_word)
1273 {
1274  // Insert an "end" for an "if" etc., if needed.
1275  // (Use of "while" allows "return" to skip the rest.
1276  // It may be clearer to use "if" and "goto",
1277  // but that violates the coding standards.)
1278 
1279  bool autofill_simple_end = (auto_endif == 2);
1280 
1281  std::size_t start = line.toStdString ().find_first_not_of (" \t");
1282 
1283  // Check if following line has the same or less indentation
1284  // Check if the following line does not start with
1285  // end* (until) (catch)
1286  if (linenr < lines () - 1)
1287  {
1288  int offset = 2; // linenr is the old line, thus, linnr+1 is the
1289  // new one and can not be taken into account
1290  std::size_t next_start;
1291  QString next_line;
1292 
1293  do // find next non-blank line
1294  {
1295  next_line = text (linenr + offset++);
1296  next_start = next_line.toStdString ().find_first_not_of (" \t\n");
1297  }
1298  while (linenr + offset < lines ()
1299  && next_start == std::string::npos);
1300 
1301  if (next_start == std::string::npos)
1302  next_start = 0;
1303  if (start == 0 && next_start == 0)
1304  return; // bug #56160, don't add at 0
1305  if (next_start > start) // more indented => don't add "end"
1306  return;
1307  if (next_start == start) // same => check if already is "end"
1308  {
1309  QRegExp rx_start = QRegExp (R"((\w+))");
1310  int tmp = rx_start.indexIn (next_line, start);
1311  if (tmp != -1 && is_end (rx_start.cap(1), first_word))
1312  return;
1313  }
1314  }
1315 
1316  // If all of the above, insert a new line, with matching indent
1317  // and either 'end' or 'end...', depending on a flag.
1318 
1319  // If we insert directly after the last line, the "end" is autoindented,
1320  // so add a dummy line.
1321  if (linenr + 2 == lines ())
1322  insertAt (QString ("\n"), linenr + 2, 0);
1323 
1324  // For try/catch/end, fill "end" first, so "catch" is top of undo stack
1325  if (first_word == "try")
1326  insertAt (QString (start, ' ')
1327  + (autofill_simple_end ? "end\n" : "end_try_catch\n"),
1328  linenr + 2, 0);
1329  else if (first_word == "unwind_protect")
1330  insertAt (QString (start, ' ')
1331  + (autofill_simple_end ? "end\n" : "end_unwind_protect\n"),
1332  linenr + 2, 0);
1333 
1334  QString next_line;
1335  if (first_word == "do")
1336  next_line = "until\n";
1337  else if (first_word == "try")
1338  next_line = "catch\n";
1339  else if (first_word == "unwind_protect")
1340  next_line = "unwind_protect_cleanup\n";
1341  else if (autofill_simple_end)
1342  next_line = "end\n";
1343  else
1344  {
1345  if (first_word == "unwind_protect")
1346  first_word = '_' + first_word;
1347  next_line = "end" + first_word + "\n";
1348  }
1349 
1350  //insertAt (QString (start, ' ') + next_line, linenr + 2, 0);
1351  insertAt (next_line, linenr + 2, 0);
1352  setIndentation (linenr + 2, indentation (linenr));
1353 }
1354 
1355 void octave_qscintilla::dragEnterEvent (QDragEnterEvent *e)
1356 {
1357  // if is not dragging a url, pass to qscintilla to handle,
1358  // otherwise ignore it so that it will be handled by
1359  // the parent
1360  if (!e->mimeData ()->hasUrls ())
1361  {
1362  QsciScintilla::dragEnterEvent (e);
1363  }
1364  else
1365  {
1366  e->ignore();
1367  }
1368 }
1369 
1371 {
1372  m_debug_mode = true;
1373 }
1374 
1376 {
1377  m_debug_mode = false;
1378 }
1379 
1381 
1382 #endif
OCTAVE_END_NAMESPACE(octave)
Base class for Octave interfaces that use Qt.
resource_manager & get_resource_manager(void)
void show_documentation_window(const QString &file)
workspace_model * get_workspace_model(void)
static void replace_line(const std::string &text, bool clear_undo=true)
Definition: cmd-edit.cc:1461
static void redisplay(void)
Definition: cmd-edit.cc:1238
static std::string get_current_line(void)
Definition: cmd-edit.cc:1447
static void set_initial_input(const std::string &text)
Definition: cmd-edit.cc:1113
static bool erase_empty_line(bool flag)
Definition: cmd-edit.cc:1318
static void accept_line(void)
Definition: cmd-edit.cc:1489
static void interrupt_event_loop(bool flag=true)
Definition: cmd-edit.cc:1645
The documentation main class derived from QSplitter.
Definition: documentation.h:99
void source_file(const std::string &file_name, const std::string &context="", bool verbose=false, bool require_file=true)
Definition: lex.h:766
@ selection
Definition: marker.h:61
void get_current_position(int *pos, int *line, int *col)
void contextmenu_break_once(const QPoint &)
void ctx_menu_run_finished_signal(bool, int, QTemporaryFile *, QTemporaryFile *, bool, bool)
void show_replace_action_tooltip(void)
void auto_close(int auto_endif, int l, const QString &line, QString &first_word)
void ctx_menu_run_finished(bool, int, QTemporaryFile *, QTemporaryFile *, bool, bool)
octave_qscintilla(QWidget *p, base_qobject &oct_qobj)
void smart_indent(bool do_smart_indent, int do_auto_close, int line, int ind_char_width)
void context_menu_break_once(int)
QString eol_string(void)
void focus_console_after_command_signal(void)
void set_word_selection(const QString &word=QString())
void show_selection_markers(int l1, int c1, int l2, int c2)
void contextmenu_break_condition(bool)
void context_menu_break_condition_signal(int)
void smart_indent_line_or_selected_text(int lineFrom, int lineTo)
base_qobject & m_octave_qobj
void cursor_position_changed(int, int)
void dragEnterEvent(QDragEnterEvent *e)
virtual void setCursorPosition(int line, int col)
virtual void contextMenuEvent(QContextMenuEvent *e)
void status_update(bool, bool)
void contextmenu_help_doc(bool)
void execute_command_in_terminal_signal(const QString &)
void context_menu_edit_signal(const QString &)
void set_selection_marker_color(const QColor &c)
void focusInEvent(QFocusEvent *focusEvent)
void handle_exit_debug_mode(void)
void interpreter_event(const fcn_callback &fcn)
void clear_selection_markers(void)
void handle_enter_debug_mode(void)
void get_global_textcursor_pos(QPoint *global_pos, QPoint *local_pos)
void create_context_menu_signal(QMenu *)
bool event(QEvent *e)
QStringList comment_string(bool comment=true)
int get_style(int pos=-1)
void contextmenu_run_temp_error(void)
int is_style_comment(int pos=-1)
void keyPressEvent(QKeyEvent *e)
void replace_all(const QString &o_str, const QString &n_str, bool re, bool cs, bool wo)
void update_rowcol_indicator_signal(int line, int col)
QPointer< QTemporaryFile > create_tmp_file(const QString &extension=QString(), const QString &contents=QString())
gui_settings * get_settings(void) const
void remove_tmp_file(QPointer< QTemporaryFile > tmp_file)
QStringList get_symbol_names(void) const
QStringList get_symbol_values(void) const
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
OCTAVE_EXPORT octave_value_list Fisdebugmode(octave::interpreter &interp, const octave_value_list &args, int)
Definition: debug.cc:1174
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 gui_pref ed_show_dbg_file("editor/show_dbg_file", QVariant(true))
const QStringList ed_comment_strings
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)
OCTAVE_EXPORT octave_value_list Fhistory(octave::interpreter &interp, const octave_value_list &args, int nargout)
Definition: oct-hist.cc:666
#define lexer
Definition: oct-parse.cc:146
static bool is_end(const QString &candidate, const QString &opening)
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
#define octave_stdout
Definition: pager.h:314
const QString key
const QVariant def