QGIS API Documentation 3.39.0-Master (47f7b3a4989)
Loading...
Searching...
No Matches
qgscodeeditor.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscodeeditor.cpp - A base code editor for QGIS and plugins. Provides
3 a base editor using QScintilla for editors
4 --------------------------------------
5 Date : 06-Oct-2013
6 Copyright : (C) 2013 by Salvatore Larosa
7 Email : lrssvtml (at) gmail (dot) com
8 ***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17#include "qgsapplication.h"
18#include "qgscodeeditor.h"
19#include "qgssettings.h"
20#include "qgssymbollayerutils.h"
21#include "qgsgui.h"
24#include "qgsstringutils.h"
25#include "qgsfontutils.h"
26
27#include <QLabel>
28#include <QWidget>
29#include <QFont>
30#include <QFontDatabase>
31#include <QDebug>
32#include <QFocusEvent>
33#include <Qsci/qscistyle.h>
34#include <QMenu>
35#include <QClipboard>
36#include <QScrollBar>
37#include <QMessageBox>
38
39QMap< QgsCodeEditorColorScheme::ColorRole, QString > QgsCodeEditor::sColorRoleToSettingsKey
40{
41 {QgsCodeEditorColorScheme::ColorRole::Default, QStringLiteral( "defaultFontColor" ) },
42 {QgsCodeEditorColorScheme::ColorRole::Keyword, QStringLiteral( "keywordFontColor" ) },
43 {QgsCodeEditorColorScheme::ColorRole::Class, QStringLiteral( "classFontColor" ) },
44 {QgsCodeEditorColorScheme::ColorRole::Method, QStringLiteral( "methodFontColor" ) },
45 {QgsCodeEditorColorScheme::ColorRole::Decoration, QStringLiteral( "decoratorFontColor" ) },
46 {QgsCodeEditorColorScheme::ColorRole::Number, QStringLiteral( "numberFontColor" ) },
47 {QgsCodeEditorColorScheme::ColorRole::Comment, QStringLiteral( "commentFontColor" ) },
48 {QgsCodeEditorColorScheme::ColorRole::CommentLine, QStringLiteral( "commentLineFontColor" ) },
49 {QgsCodeEditorColorScheme::ColorRole::CommentBlock, QStringLiteral( "commentBlockFontColor" ) },
50 {QgsCodeEditorColorScheme::ColorRole::Background, QStringLiteral( "paperBackgroundColor" ) },
51 {QgsCodeEditorColorScheme::ColorRole::Cursor, QStringLiteral( "cursorColor" ) },
52 {QgsCodeEditorColorScheme::ColorRole::CaretLine, QStringLiteral( "caretLineColor" ) },
53 {QgsCodeEditorColorScheme::ColorRole::Operator, QStringLiteral( "operatorFontColor" ) },
54 {QgsCodeEditorColorScheme::ColorRole::QuotedOperator, QStringLiteral( "quotedOperatorFontColor" ) },
55 {QgsCodeEditorColorScheme::ColorRole::Identifier, QStringLiteral( "identifierFontColor" ) },
56 {QgsCodeEditorColorScheme::ColorRole::QuotedIdentifier, QStringLiteral( "quotedIdentifierFontColor" ) },
57 {QgsCodeEditorColorScheme::ColorRole::Tag, QStringLiteral( "tagFontColor" ) },
58 {QgsCodeEditorColorScheme::ColorRole::UnknownTag, QStringLiteral( "unknownTagFontColor" ) },
59 {QgsCodeEditorColorScheme::ColorRole::SingleQuote, QStringLiteral( "singleQuoteFontColor" ) },
60 {QgsCodeEditorColorScheme::ColorRole::DoubleQuote, QStringLiteral( "doubleQuoteFontColor" ) },
61 {QgsCodeEditorColorScheme::ColorRole::TripleSingleQuote, QStringLiteral( "tripleSingleQuoteFontColor" ) },
62 {QgsCodeEditorColorScheme::ColorRole::TripleDoubleQuote, QStringLiteral( "tripleDoubleQuoteFontColor" ) },
63 {QgsCodeEditorColorScheme::ColorRole::MarginBackground, QStringLiteral( "marginBackgroundColor" ) },
64 {QgsCodeEditorColorScheme::ColorRole::MarginForeground, QStringLiteral( "marginForegroundColor" ) },
65 {QgsCodeEditorColorScheme::ColorRole::SelectionBackground, QStringLiteral( "selectionBackgroundColor" ) },
66 {QgsCodeEditorColorScheme::ColorRole::SelectionForeground, QStringLiteral( "selectionForegroundColor" ) },
67 {QgsCodeEditorColorScheme::ColorRole::MatchedBraceBackground, QStringLiteral( "matchedBraceBackground" ) },
68 {QgsCodeEditorColorScheme::ColorRole::MatchedBraceForeground, QStringLiteral( "matchedBraceColor" ) },
69 {QgsCodeEditorColorScheme::ColorRole::Edge, QStringLiteral( "edgeColor" ) },
70 {QgsCodeEditorColorScheme::ColorRole::Fold, QStringLiteral( "foldColor" ) },
71 {QgsCodeEditorColorScheme::ColorRole::Error, QStringLiteral( "stderrFontColor" ) },
72 {QgsCodeEditorColorScheme::ColorRole::ErrorBackground, QStringLiteral( "stderrBackgroundColor" ) },
73 {QgsCodeEditorColorScheme::ColorRole::FoldIconForeground, QStringLiteral( "foldIconForeground" ) },
74 {QgsCodeEditorColorScheme::ColorRole::FoldIconHalo, QStringLiteral( "foldIconHalo" ) },
75 {QgsCodeEditorColorScheme::ColorRole::IndentationGuide, QStringLiteral( "indentationGuide" ) },
76 {QgsCodeEditorColorScheme::ColorRole::SearchMatchBackground, QStringLiteral( "searchMatchBackground" ) }
77};
78
79QgsCodeEditor::QgsCodeEditor( QWidget *parent, const QString &title, bool folding, bool margin, QgsCodeEditor::Flags flags, QgsCodeEditor::Mode mode )
80 : QsciScintilla( parent )
81 , mWidgetTitle( title )
82 , mMargin( margin )
83 , mFlags( flags )
84 , mMode( mode )
85{
86 if ( !parent && mWidgetTitle.isEmpty() )
87 {
88 setWindowTitle( QStringLiteral( "Text Editor" ) );
89 }
90 else
91 {
92 setWindowTitle( mWidgetTitle );
93 }
94
95 if ( folding )
97
98 mSoftHistory.append( QString() );
99
100 setSciWidget();
101 setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
102
103 SendScintilla( SCI_SETADDITIONALSELECTIONTYPING, 1 );
104 SendScintilla( SCI_SETMULTIPASTE, 1 );
105 SendScintilla( SCI_SETVIRTUALSPACEOPTIONS, SCVS_RECTANGULARSELECTION );
106
107 SendScintilla( SCI_SETMARGINTYPEN, static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), SC_MARGIN_SYMBOL );
108 SendScintilla( SCI_SETMARGINMASKN, static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 1 << MARKER_NUMBER );
109 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 0 );
110 setAnnotationDisplay( QsciScintilla::AnnotationBoxed );
111
112 connect( QgsGui::instance(), &QgsGui::optionsChanged, this, [ = ]
113 {
114 setSciWidget();
116 } );
117
118 switch ( mMode )
119 {
121 break;
122
124 {
125 // Don't want to see the horizontal scrollbar at all
126 SendScintilla( QsciScintilla::SCI_SETHSCROLLBAR, 0 );
127
128 setWrapMode( QsciScintilla::WrapCharacter );
129 break;
130 }
131
133 {
134 // Don't want to see the horizontal scrollbar at all
135 SendScintilla( QsciScintilla::SCI_SETHSCROLLBAR, 0 );
136
137 setWrapMode( QsciScintilla::WrapCharacter );
138 SendScintilla( QsciScintilla::SCI_EMPTYUNDOBUFFER );
139 break;
140 }
141 }
142
143#if QSCINTILLA_VERSION < 0x020d03
144 installEventFilter( this );
145#endif
146}
147
148// Workaround a bug in QScintilla 2.8.X
149void QgsCodeEditor::focusOutEvent( QFocusEvent *event )
150{
151#if QSCINTILLA_VERSION >= 0x020800 && QSCINTILLA_VERSION < 0x020900
152 if ( event->reason() != Qt::ActiveWindowFocusReason )
153 {
154 /* There's a bug in all QScintilla 2.8.X, where
155 a focus out event that is not due to ActiveWindowFocusReason doesn't
156 lead to the bliking caret being disabled. The hack consists in making
157 QsciScintilla::focusOutEvent believe that the event is a ActiveWindowFocusReason
158 The bug was fixed in 2.9 per:
159 2015-04-14 Phil Thompson <[email protected]>
160
161 * qt/qsciscintillabase.cpp:
162 Fixed a problem notifying when focus is lost to another application
163 widget.
164 [41734678234e]
165 */
166 QFocusEvent newFocusEvent( QEvent::FocusOut, Qt::ActiveWindowFocusReason );
167 QsciScintilla::focusOutEvent( &newFocusEvent );
168 }
169 else
170#endif
171 {
172 QsciScintilla::focusOutEvent( event );
173 }
174}
175
176// This workaround a likely bug in QScintilla. The ESC key should not be consumned
177// by the main entry, so that the default behavior (Dialog closing) can trigger,
178// but only is the auto-completion suggestion list isn't displayed
179void QgsCodeEditor::keyPressEvent( QKeyEvent *event )
180{
181 if ( isListActive() )
182 {
183 QsciScintilla::keyPressEvent( event );
184 return;
185 }
186
187 if ( event->key() == Qt::Key_Escape )
188 {
189 // Shortcut QScintilla and redirect the event to the QWidget handler
190 QWidget::keyPressEvent( event ); // NOLINT(bugprone-parent-virtual-call) clazy:exclude=skipped-base-method
191 return;
192 }
193
195 {
196 switch ( event->key() )
197 {
198 case Qt::Key_Return:
199 case Qt::Key_Enter:
200 runCommand( text() );
201 updatePrompt();
202 return;
203
204 case Qt::Key_Down:
206 updatePrompt();
207 return;
208
209 case Qt::Key_Up:
211 updatePrompt();
212 return;
213
214 default:
215 break;
216 }
217 }
218
219 const bool ctrlModifier = event->modifiers() & Qt::ControlModifier;
220 const bool altModifier = event->modifiers() & Qt::AltModifier;
221
222 // Ctrl+Alt+F: reformat code
224 if ( !isReadOnly() && canReformat && ctrlModifier && altModifier && event->key() == Qt::Key_F )
225 {
226 event->accept();
227 reformatCode();
228 return;
229 }
230
231 // Toggle comment when user presses Ctrl+:
233 if ( !isReadOnly() && canToggle && ctrlModifier && event->key() == Qt::Key_Colon )
234 {
235 event->accept();
237 return;
238 }
239
240 QsciScintilla::keyPressEvent( event );
241
242}
243
244void QgsCodeEditor::contextMenuEvent( QContextMenuEvent *event )
245{
246 switch ( mMode )
247 {
249 {
250 QMenu *menu = createStandardContextMenu();
251 menu->setAttribute( Qt::WA_DeleteOnClose );
252
255 {
256 menu->addSeparator();
257 }
258
260 {
261 QAction *reformatAction = new QAction( tr( "Reformat Code" ), menu );
262 reformatAction->setShortcut( QStringLiteral( "Ctrl+Alt+F" ) );
263 reformatAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconFormatCode.svg" ) ) );
264 reformatAction->setEnabled( !isReadOnly() );
265 connect( reformatAction, &QAction::triggered, this, &QgsCodeEditor::reformatCode );
266 menu->addAction( reformatAction );
267 }
268
270 {
271 QAction *syntaxCheckAction = new QAction( tr( "Check Syntax" ), menu );
272 syntaxCheckAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconSyntaxErrorConsole.svg" ) ) );
273 connect( syntaxCheckAction, &QAction::triggered, this, &QgsCodeEditor::checkSyntax );
274 menu->addAction( syntaxCheckAction );
275 }
276
278 {
279 QAction *toggleCommentAction = new QAction( tr( "Toggle Comment" ), menu );
280 toggleCommentAction->setShortcut( QStringLiteral( "Ctrl+:" ) );
281 toggleCommentAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconCommentEditorConsole.svg" ) ) );
282 toggleCommentAction->setEnabled( !isReadOnly() );
283 connect( toggleCommentAction, &QAction::triggered, this, &QgsCodeEditor::toggleComment );
284 menu->addAction( toggleCommentAction );
285 }
286
287 populateContextMenu( menu );
288
289 menu->exec( mapToGlobal( event->pos() ) );
290 break;
291 }
292
294 {
295 QMenu *menu = new QMenu( this );
296 QMenu *historySubMenu = new QMenu( tr( "Command History" ), menu );
297
298 historySubMenu->addAction( tr( "Show" ), this, &QgsCodeEditor::showHistory, QStringLiteral( "Ctrl+Shift+SPACE" ) );
299 historySubMenu->addAction( tr( "Clear File" ), this, &QgsCodeEditor::clearPersistentHistory );
300 historySubMenu->addAction( tr( "Clear Session" ), this, &QgsCodeEditor::clearSessionHistory );
301
302 menu->addMenu( historySubMenu );
303 menu->addSeparator();
304
305 QAction *copyAction = menu->addAction( QgsApplication::getThemeIcon( "mActionEditCopy.svg" ), tr( "Copy" ), this, &QgsCodeEditor::copy, QKeySequence::Copy );
306 QAction *pasteAction = menu->addAction( QgsApplication::getThemeIcon( "mActionEditPaste.svg" ), tr( "Paste" ), this, &QgsCodeEditor::paste, QKeySequence::Paste );
307 copyAction->setEnabled( hasSelectedText() );
308 pasteAction->setEnabled( !QApplication::clipboard()->text().isEmpty() );
309
310 populateContextMenu( menu );
311
312 menu->exec( mapToGlobal( event->pos() ) );
313 break;
314 }
315
317 QsciScintilla::contextMenuEvent( event );
318 break;
319 }
320}
321
322bool QgsCodeEditor::eventFilter( QObject *watched, QEvent *event )
323{
324#if QSCINTILLA_VERSION < 0x020d03
325 if ( watched == this && event->type() == QEvent::InputMethod )
326 {
327 // swallow input method events, which cause loss of selected text.
328 // See https://sourceforge.net/p/scintilla/bugs/1913/ , which was ported to QScintilla
329 // in version 2.13.3
330 return true;
331 }
332#endif
333
334 return QsciScintilla::eventFilter( watched, event );
335}
336
341
343{
344 if ( mUseDefaultSettings )
345 return color( role );
346
347 if ( !mOverrideColors )
348 {
349 return defaultColor( role, mColorScheme );
350 }
351 else
352 {
353 const QColor color = mCustomColors.value( role );
354 return !color.isValid() ? defaultColor( role ) : color;
355 }
356}
357
359{
360 if ( mUseDefaultSettings )
361 return getMonospaceFont();
362
363 QFont font = QFontDatabase::systemFont( QFontDatabase::FixedFont );
364
365 const QgsSettings settings;
366 if ( !mFontFamily.isEmpty() )
367 QgsFontUtils::setFontFamily( font, mFontFamily );
368
369#ifdef Q_OS_MAC
370 if ( mFontSize > 0 )
371 font.setPointSize( mFontSize );
372 else
373 {
374 // The font size gotten from getMonospaceFont() is too small on Mac
375 font.setPointSize( QLabel().font().pointSize() );
376 }
377#else
378 if ( mFontSize > 0 )
379 font.setPointSize( mFontSize );
380 else
381 {
382 const int fontSize = settings.value( QStringLiteral( "qgis/stylesheet/fontPointSize" ), 10 ).toInt();
383 font.setPointSize( fontSize );
384 }
385#endif
386 font.setBold( false );
387
388 return font;
389}
390
392{
393 updateFolding();
394
397
398 SendScintilla( SCI_MARKERSETFORE, SC_MARKNUM_FOLDEROPEN, lexerColor( QgsCodeEditorColorScheme::ColorRole::FoldIconHalo ) );
399 SendScintilla( SCI_MARKERSETBACK, SC_MARKNUM_FOLDEROPEN, lexerColor( QgsCodeEditorColorScheme::ColorRole::FoldIconForeground ) );
400 SendScintilla( SCI_MARKERSETFORE, SC_MARKNUM_FOLDER, lexerColor( QgsCodeEditorColorScheme::ColorRole::FoldIconHalo ) );
401 SendScintilla( SCI_MARKERSETBACK, SC_MARKNUM_FOLDER, lexerColor( QgsCodeEditorColorScheme::ColorRole::FoldIconForeground ) );
402 SendScintilla( SCI_STYLESETFORE, STYLE_INDENTGUIDE, lexerColor( QgsCodeEditorColorScheme::ColorRole::IndentationGuide ) );
403 SendScintilla( SCI_STYLESETBACK, STYLE_INDENTGUIDE, lexerColor( QgsCodeEditorColorScheme::ColorRole::IndentationGuide ) );
404
405 SendScintilla( QsciScintilla::SCI_INDICSETSTYLE, SEARCH_RESULT_INDICATOR, QsciScintilla::INDIC_STRAIGHTBOX );
406 SendScintilla( QsciScintilla::SCI_INDICSETFORE, SEARCH_RESULT_INDICATOR, lexerColor( QgsCodeEditorColorScheme::ColorRole::SearchMatchBackground ) );
407 SendScintilla( QsciScintilla::SCI_INDICSETALPHA, SEARCH_RESULT_INDICATOR, 100 );
408 SendScintilla( QsciScintilla::SCI_INDICSETUNDER, SEARCH_RESULT_INDICATOR, true );
409 SendScintilla( QsciScintilla::SCI_INDICGETOUTLINEALPHA, SEARCH_RESULT_INDICATOR, 255 );
410
412 {
413 setCaretLineVisible( false );
414 setLineNumbersVisible( false ); // NO linenumbers for the input line
415 // Margin 1 is used for the '>' prompt (console input)
416 setMarginLineNumbers( 1, true );
417 setMarginWidth( 1, "00000" );
418 setMarginType( 1, QsciScintilla::MarginType::TextMarginRightJustified );
419 setMarginsBackgroundColor( color( QgsCodeEditorColorScheme::ColorRole::Background ) );
420 setEdgeMode( QsciScintilla::EdgeNone );
421 }
422}
423
424void QgsCodeEditor::setSciWidget()
425{
426 const QFont font = lexerFont();
427 setFont( font );
428
429 setUtf8( true );
430 setCaretLineVisible( true );
431 setCaretLineBackgroundColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::CaretLine ) );
432 setCaretForegroundColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Cursor ) );
435
436 setBraceMatching( QsciScintilla::SloppyBraceMatch );
439
440 setLineNumbersVisible( false );
441
442 // temporarily disable folding, will be enabled later if required by updateFolding()
443 setFolding( QsciScintilla::NoFoldStyle );
444 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::FoldingControls ), 0 );
445
446 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 0 );
447
450 setIndentationGuidesForegroundColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::MarginForeground ) );
451 setIndentationGuidesBackgroundColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::MarginBackground ) );
452 // whether margin will be shown
453 updateFolding();
454 const QColor foldColor = lexerColor( QgsCodeEditorColorScheme::ColorRole::Fold );
455 setFoldMarginColors( foldColor, foldColor );
456 // indentation
457 setAutoIndent( true );
458 setIndentationWidth( 4 );
459 setTabIndents( true );
460 setBackspaceUnindents( true );
461 setTabWidth( 4 );
462 // autocomplete
463 setAutoCompletionThreshold( 2 );
464 setAutoCompletionSource( QsciScintilla::AcsAPIs );
465
466 markerDefine( QgsApplication::getThemePixmap( "console/iconSyntaxErrorConsoleParams.svg", lexerColor( QgsCodeEditorColorScheme::ColorRole::Error ),
468}
469
470void QgsCodeEditor::setTitle( const QString &title )
471{
472 setWindowTitle( title );
473}
474
479
484
486{
487 switch ( language )
488 {
490 return tr( "CSS" );
492 return tr( "Expression" );
494 return tr( "HTML" );
496 return tr( "JavaScript" );
498 return tr( "JSON" );
500 return tr( "Python" );
502 return tr( "R" );
504 return tr( "SQL" );
506 return tr( "Batch" );
508 return tr( "Bash" );
510 return QString();
511 }
513}
514
516{
517 mMargin = margin;
518 if ( margin )
519 {
520 QFont marginFont = lexerFont();
521 marginFont.setPointSize( 10 );
522 setMarginLineNumbers( 0, true );
523 setMarginsFont( marginFont );
524 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), QStringLiteral( "00000" ) );
527 }
528 else
529 {
530 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), 0 );
531 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 0 );
532 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::FoldingControls ), 0 );
533 }
534}
535
537{
538 if ( visible )
539 {
540 QFont marginFont = lexerFont();
541 marginFont.setPointSize( 10 );
542 setMarginLineNumbers( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), true );
543 setMarginsFont( marginFont );
544 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), QStringLiteral( "00000" ) );
547 }
548 else
549 {
550 setMarginLineNumbers( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), false );
551 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), 0 );
552 }
553}
554
556{
557 return marginLineNumbers( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ) );
558}
559
561{
562 if ( folding )
563 {
565 }
566 else
567 {
568 mFlags &= ~( static_cast< int >( QgsCodeEditor::Flag::CodeFolding ) );
569 }
570 updateFolding();
571}
572
577
578void QgsCodeEditor::updateFolding()
579{
581 {
582 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::FoldingControls ), "0" );
585 setFolding( QsciScintilla::PlainFoldStyle );
586 }
587 else
588 {
589 setFolding( QsciScintilla::NoFoldStyle );
590 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::FoldingControls ), 0 );
591 }
592}
593
594bool QgsCodeEditor::readHistoryFile()
595{
596 if ( mHistoryFilePath.isEmpty() || !QFile::exists( mHistoryFilePath ) )
597 return false;
598
599 QFile file( mHistoryFilePath );
600 if ( file.open( QIODevice::ReadOnly ) )
601 {
602 QTextStream stream( &file );
603#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
604 // Always use UTF-8
605 stream.setCodec( "UTF-8" );
606#endif
607 QString line;
608 while ( !stream.atEnd() )
609 {
610 line = stream.readLine(); // line of text excluding '\n'
611 mHistory.append( line );
612 }
613 syncSoftHistory();
614 return true;
615 }
616
617 return false;
618}
619
620void QgsCodeEditor::syncSoftHistory()
621{
622 mSoftHistory = mHistory;
623 mSoftHistory.append( QString() );
624 mSoftHistoryIndex = mSoftHistory.length() - 1;
625}
626
628{
629 mSoftHistory[mSoftHistoryIndex] = text();
630}
631
632void QgsCodeEditor::updateHistory( const QStringList &commands, bool skipSoftHistory )
633{
634 if ( commands.size() > 1 )
635 {
636 mHistory.append( commands );
637 }
638 else if ( !commands.value( 0 ).isEmpty() )
639 {
640 const QString command = commands.value( 0 );
641 if ( mHistory.empty() || command != mHistory.constLast() )
642 mHistory.append( command );
643 }
644
645 if ( !skipSoftHistory )
646 syncSoftHistory();
647}
648
650{
651
652}
653
654QString QgsCodeEditor::reformatCodeString( const QString &string )
655{
656 return string;
657}
658
659void QgsCodeEditor::showMessage( const QString &title, const QString &message, Qgis::MessageLevel level )
660{
661 switch ( level )
662 {
663 case Qgis::Info:
664 case Qgis::Success:
665 case Qgis::NoLevel:
666 QMessageBox::information( this, title, message );
667 break;
668
669 case Qgis::Warning:
670 QMessageBox::warning( this, title, message );
671 break;
672
673 case Qgis::Critical:
674 QMessageBox::critical( this, title, message );
675 break;
676 }
677}
678
680{
681 if ( mInterpreter )
682 {
683 const QString prompt = mInterpreter->promptForState( mInterpreter->currentState() );
684 SendScintilla( QsciScintilla::SCI_MARGINSETTEXT, static_cast< uintptr_t >( 0 ), prompt.toUtf8().constData() );
685 }
686}
687
689{
690 return mInterpreter;
691}
692
694{
695 mInterpreter = newInterpreter;
696 updatePrompt();
697}
698
699// Find the source substring index that most closely matches the target string
700int findMinimalDistanceIndex( const QString &source, const QString &target )
701{
702 const int index = std::min( source.length(), target.length() );
703
704 const int d0 = QgsStringUtils::levenshteinDistance( source.left( index ), target );
705 if ( d0 == 0 )
706 return index;
707
708 int refDistanceMore = d0;
709 int refIndexMore = index;
710 if ( index < source.length() - 1 )
711 {
712 while ( true )
713 {
714 const int newDistance = QgsStringUtils::levenshteinDistance( source.left( refIndexMore + 1 ), target );
715 if ( newDistance <= refDistanceMore )
716 {
717 refDistanceMore = newDistance;
718 refIndexMore++;
719 if ( refIndexMore == source.length() - 1 )
720 break;
721 }
722 else
723 {
724 break;
725 }
726 }
727 }
728
729 int refDistanceLess = d0;
730 int refIndexLess = index;
731 if ( index > 0 )
732 {
733 while ( true )
734 {
735 const int newDistance = QgsStringUtils::levenshteinDistance( source.left( refIndexLess - 1 ), target );
736 if ( newDistance <= refDistanceLess )
737 {
738 refDistanceLess = newDistance;
739 refIndexLess--;
740 if ( refIndexLess == 0 )
741 break;
742 }
743 else
744 {
745 break;
746 }
747 }
748 }
749
750 if ( refDistanceMore < refDistanceLess )
751 return refIndexMore;
752 else
753 return refIndexLess;
754}
755
757{
759 return;
760
761 const QString textBeforeCursor = text( 0, linearPosition() );
762 const QString originalText = text();
763 const QString newText = reformatCodeString( originalText );
764
765 if ( originalText == newText )
766 return;
767
768 // try to preserve the cursor position and scroll position
769 const int oldScrollValue = verticalScrollBar()->value();
770 const int linearIndex = findMinimalDistanceIndex( newText, textBeforeCursor );
771
772 beginUndoAction();
773 selectAll();
774 removeSelectedText();
775 insert( newText );
776 setLinearPosition( linearIndex );
777 verticalScrollBar()->setValue( oldScrollValue );
778 endUndoAction();
779}
780
782{
783 return true;
784}
785
787{
788
789}
790
791QStringList QgsCodeEditor::history() const
792{
793 return mHistory;
794}
795
796void QgsCodeEditor::runCommand( const QString &command, bool skipHistory )
797{
798 if ( !skipHistory )
799 {
800 updateHistory( { command } );
803 }
804
805 if ( mInterpreter )
806 mInterpreter->exec( command );
807
808 clear();
810}
811
813{
814 mHistory.clear();
815 readHistoryFile();
816 syncSoftHistory();
817
819}
820
822{
823 mHistory.clear();
824
825 if ( !mHistoryFilePath.isEmpty() && QFile::exists( mHistoryFilePath ) )
826 {
827 QFile file( mHistoryFilePath );
828 file.open( QFile::WriteOnly | QFile::Truncate );
829 }
830
832}
833
835{
836 if ( mHistoryFilePath.isEmpty() )
837 return false;
838
839 QFile f( mHistoryFilePath );
840 if ( !f.open( QFile::WriteOnly | QIODevice::Truncate ) )
841 {
842 return false;
843 }
844
845 QTextStream ts( &f );
846#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
847 ts.setCodec( "UTF-8" );
848#endif
849 for ( const QString &command : std::as_const( mHistory ) )
850 {
851 ts << command + '\n';
852 }
853 return true;
854}
855
857{
858 if ( mSoftHistoryIndex < mSoftHistory.length() - 1 && !mSoftHistory.isEmpty() )
859 {
860 mSoftHistoryIndex += 1;
861 setText( mSoftHistory[mSoftHistoryIndex] );
863 }
864}
865
867{
868 if ( mSoftHistoryIndex > 0 && !mSoftHistory.empty() )
869 {
870 mSoftHistoryIndex -= 1;
871 setText( mSoftHistory[mSoftHistoryIndex] );
873 }
874}
875
877{
878 QgsCodeEditorHistoryDialog *dialog = new QgsCodeEditorHistoryDialog( this, this );
879 dialog->setAttribute( Qt::WA_DeleteOnClose );
880
881 dialog->show();
882 dialog->activateWindow();
883}
884
886{
887 // remove item from the command history (just for the current session)
888 mHistory.removeAt( index );
889 mSoftHistory.removeAt( index );
890 if ( index < mSoftHistoryIndex )
891 {
892 mSoftHistoryIndex -= 1;
893 if ( mSoftHistoryIndex < 0 )
894 mSoftHistoryIndex = mSoftHistory.length() - 1;
895 }
896}
897
898void QgsCodeEditor::insertText( const QString &text )
899{
900 // Insert the text or replace selected text
901 if ( hasSelectedText() )
902 {
903 replaceSelectedText( text );
904 }
905 else
906 {
907 int line, index;
908 getCursorPosition( &line, &index );
909 insertAt( text, line, index );
910 setCursorPosition( line, index + text.length() );
911 }
912}
913
915{
916 if ( theme.isEmpty() && QgsApplication::themeName() == QLatin1String( "default" ) )
917 {
918 // if using default theme, take certain colors from the palette
919 const QPalette pal = qApp->palette();
920
921 switch ( role )
922 {
924 return pal.color( QPalette::Highlight );
926 return pal.color( QPalette::HighlightedText );
927 default:
928 break;
929 }
930 }
931 else if ( theme.isEmpty() )
932 {
933 // non default theme (e.g. Blend of Gray). Take colors from theme ini file...
934 const QSettings ini( QgsApplication::uiThemes().value( QgsApplication::themeName() ) + "/qscintilla.ini", QSettings::IniFormat );
935
936 static const QMap< QgsCodeEditorColorScheme::ColorRole, QString > sColorRoleToIniKey
937 {
938 {QgsCodeEditorColorScheme::ColorRole::Default, QStringLiteral( "python/defaultFontColor" ) },
939 {QgsCodeEditorColorScheme::ColorRole::Keyword, QStringLiteral( "python/keywordFontColor" ) },
940 {QgsCodeEditorColorScheme::ColorRole::Class, QStringLiteral( "python/classFontColor" ) },
941 {QgsCodeEditorColorScheme::ColorRole::Method, QStringLiteral( "python/methodFontColor" ) },
942 {QgsCodeEditorColorScheme::ColorRole::Decoration, QStringLiteral( "python/decoratorFontColor" ) },
943 {QgsCodeEditorColorScheme::ColorRole::Number, QStringLiteral( "python/numberFontColor" ) },
944 {QgsCodeEditorColorScheme::ColorRole::Comment, QStringLiteral( "python/commentFontColor" ) },
945 {QgsCodeEditorColorScheme::ColorRole::CommentLine, QStringLiteral( "sql/commentLineFontColor" ) },
946 {QgsCodeEditorColorScheme::ColorRole::CommentBlock, QStringLiteral( "python/commentBlockFontColor" ) },
947 {QgsCodeEditorColorScheme::ColorRole::Background, QStringLiteral( "python/paperBackgroundColor" ) },
948 {QgsCodeEditorColorScheme::ColorRole::Cursor, QStringLiteral( "cursorColor" ) },
949 {QgsCodeEditorColorScheme::ColorRole::CaretLine, QStringLiteral( "caretLineColor" ) },
950 {QgsCodeEditorColorScheme::ColorRole::Operator, QStringLiteral( "sql/operatorFontColor" ) },
951 {QgsCodeEditorColorScheme::ColorRole::QuotedOperator, QStringLiteral( "sql/QuotedOperatorFontColor" ) },
952 {QgsCodeEditorColorScheme::ColorRole::Identifier, QStringLiteral( "sql/identifierFontColor" ) },
953 {QgsCodeEditorColorScheme::ColorRole::QuotedIdentifier, QStringLiteral( "sql/QuotedIdentifierFontColor" ) },
954 {QgsCodeEditorColorScheme::ColorRole::Tag, QStringLiteral( "html/tagFontColor" ) },
955 {QgsCodeEditorColorScheme::ColorRole::UnknownTag, QStringLiteral( "html/unknownTagFontColor" ) },
956 {QgsCodeEditorColorScheme::ColorRole::SingleQuote, QStringLiteral( "sql/singleQuoteFontColor" ) },
957 {QgsCodeEditorColorScheme::ColorRole::DoubleQuote, QStringLiteral( "sql/doubleQuoteFontColor" ) },
958 {QgsCodeEditorColorScheme::ColorRole::TripleSingleQuote, QStringLiteral( "python/tripleSingleQuoteFontColor" ) },
959 {QgsCodeEditorColorScheme::ColorRole::TripleDoubleQuote, QStringLiteral( "python/tripleDoubleQuoteFontColor" ) },
960 {QgsCodeEditorColorScheme::ColorRole::MarginBackground, QStringLiteral( "marginBackgroundColor" ) },
961 {QgsCodeEditorColorScheme::ColorRole::MarginForeground, QStringLiteral( "marginForegroundColor" ) },
962 {QgsCodeEditorColorScheme::ColorRole::SelectionBackground, QStringLiteral( "selectionBackgroundColor" ) },
963 {QgsCodeEditorColorScheme::ColorRole::SelectionForeground, QStringLiteral( "selectionForegroundColor" ) },
964 {QgsCodeEditorColorScheme::ColorRole::MatchedBraceBackground, QStringLiteral( "matchedBraceBackground" ) },
965 {QgsCodeEditorColorScheme::ColorRole::MatchedBraceForeground, QStringLiteral( "matchedBraceColor" ) },
966 {QgsCodeEditorColorScheme::ColorRole::Edge, QStringLiteral( "edgeColor" ) },
967 {QgsCodeEditorColorScheme::ColorRole::Fold, QStringLiteral( "foldColor" ) },
968 {QgsCodeEditorColorScheme::ColorRole::Error, QStringLiteral( "stderrFontColor" ) },
969 {QgsCodeEditorColorScheme::ColorRole::ErrorBackground, QStringLiteral( "stderrBackground" ) },
970 {QgsCodeEditorColorScheme::ColorRole::FoldIconForeground, QStringLiteral( "foldIconForeground" ) },
971 {QgsCodeEditorColorScheme::ColorRole::FoldIconHalo, QStringLiteral( "foldIconHalo" ) },
972 {QgsCodeEditorColorScheme::ColorRole::IndentationGuide, QStringLiteral( "indentationGuide" ) },
973 {QgsCodeEditorColorScheme::ColorRole::SearchMatchBackground, QStringLiteral( "searchMatchBackground" ) },
974 };
975
976 const QgsCodeEditorColorScheme defaultScheme = QgsGui::codeEditorColorSchemeRegistry()->scheme( QStringLiteral( "default" ) );
977 return QgsSymbolLayerUtils::decodeColor( ini.value( sColorRoleToIniKey.value( role ), defaultScheme.color( role ).name() ).toString() );
978 }
979
980 const QgsCodeEditorColorScheme scheme = QgsGui::codeEditorColorSchemeRegistry()->scheme( theme.isEmpty() ? QStringLiteral( "default" ) : theme );
981 return scheme.color( role );
982}
983
985{
986 const QgsSettings settings;
987 if ( !settings.value( QStringLiteral( "codeEditor/overrideColors" ), false, QgsSettings::Gui ).toBool() )
988 {
989 const QString theme = settings.value( QStringLiteral( "codeEditor/colorScheme" ), QString(), QgsSettings::Gui ).toString();
990 return defaultColor( role, theme );
991 }
992 else
993 {
994 const QString color = settings.value( QStringLiteral( "codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), QString(), QgsSettings::Gui ).toString();
995 return color.isEmpty() ? defaultColor( role ) : QgsSymbolLayerUtils::decodeColor( color );
996 }
997}
998
1000{
1001 QgsSettings settings;
1002 if ( color.isValid() )
1003 {
1004 settings.setValue( QStringLiteral( "codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), color.name(), QgsSettings::Gui );
1005 }
1006 else
1007 {
1008 settings.remove( QStringLiteral( "codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), QgsSettings::Gui );
1009 }
1010}
1011
1012// Settings for font and fontsize
1013bool QgsCodeEditor::isFixedPitch( const QFont &font )
1014{
1015 return font.fixedPitch();
1016}
1017
1019{
1020 QFont font = QFontDatabase::systemFont( QFontDatabase::FixedFont );
1021
1022 const QgsSettings settings;
1023 if ( !settings.value( QStringLiteral( "codeEditor/fontfamily" ), QString(), QgsSettings::Gui ).toString().isEmpty() )
1024 QgsFontUtils::setFontFamily( font, settings.value( QStringLiteral( "codeEditor/fontfamily" ), QString(), QgsSettings::Gui ).toString() );
1025
1026 const int fontSize = settings.value( QStringLiteral( "codeEditor/fontsize" ), 0, QgsSettings::Gui ).toInt();
1027
1028#ifdef Q_OS_MAC
1029 if ( fontSize > 0 )
1030 font.setPointSize( fontSize );
1031 else
1032 {
1033 // The font size gotten from getMonospaceFont() is too small on Mac
1034 font.setPointSize( QLabel().font().pointSize() );
1035 }
1036#else
1037 if ( fontSize > 0 )
1038 font.setPointSize( fontSize );
1039 else
1040 {
1041 const int fontSize = settings.value( QStringLiteral( "qgis/stylesheet/fontPointSize" ), 10 ).toInt();
1042 font.setPointSize( fontSize );
1043 }
1044#endif
1045 font.setBold( false );
1046
1047 return font;
1048}
1049
1050void QgsCodeEditor::setCustomAppearance( const QString &scheme, const QMap<QgsCodeEditorColorScheme::ColorRole, QColor> &customColors, const QString &fontFamily, int fontSize )
1051{
1052 mUseDefaultSettings = false;
1053 mOverrideColors = !customColors.isEmpty();
1054 mColorScheme = scheme;
1055 mCustomColors = customColors;
1056 mFontFamily = fontFamily;
1057 mFontSize = fontSize;
1058
1059 setSciWidget();
1061}
1062
1063void QgsCodeEditor::addWarning( const int lineNumber, const QString &warning )
1064{
1065 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), "000" );
1066 markerAdd( lineNumber, MARKER_NUMBER );
1067 QFont font = lexerFont();
1068 font.setItalic( true );
1069 const QsciStyle styleAnn = QsciStyle( -1, QStringLiteral( "Annotation" ),
1072 font,
1073 true );
1074 annotate( lineNumber, warning, styleAnn );
1075 mWarningLines.push_back( lineNumber );
1076}
1077
1079{
1080 for ( const int line : mWarningLines )
1081 {
1082 markerDelete( line );
1083 clearAnnotations( line );
1084 }
1085 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 0 );
1086 mWarningLines.clear();
1087}
1088
1090{
1091 int line = 0;
1092 int index = 0;
1093 getCursorPosition( &line, &index );
1094 return line == lines() - 1;
1095}
1096
1097void QgsCodeEditor::setHistoryFilePath( const QString &path )
1098{
1099 mHistoryFilePath = path;
1100 readHistoryFile();
1101}
1102
1104{
1105 setCursorPosition( 0, 0 );
1106 ensureCursorVisible();
1107 ensureLineVisible( 0 );
1108
1109 if ( mMode == QgsCodeEditor::Mode::CommandInput )
1110 updatePrompt();
1111}
1112
1114{
1115 const int endLine = lines() - 1;
1116 const int endLineLength = lineLength( endLine );
1117 setCursorPosition( endLine, endLineLength );
1118 ensureCursorVisible();
1119 ensureLineVisible( endLine );
1120
1121 if ( mMode == QgsCodeEditor::Mode::CommandInput )
1122 updatePrompt();
1123}
1124
1126{
1127 int line, index;
1128 getCursorPosition( &line, &index );
1129 return positionFromLineIndex( line, index );
1130}
1131
1133{
1134 int line, index;
1135 lineIndexFromPosition( linearIndex, &line, &index );
1136 setCursorPosition( line, index );
1137}
1138
1140{
1141 int startLine, startIndex, _;
1142 getSelection( &startLine, &startIndex, &_, &_ );
1143 if ( startLine == -1 )
1144 {
1145 return linearPosition();
1146 }
1147 return positionFromLineIndex( startLine, startIndex );
1148}
1149
1151{
1152 int endLine, endIndex, _;
1153 getSelection( &_, &_, &endLine, &endIndex );
1154 if ( endLine == -1 )
1155 {
1156 return linearPosition();
1157 }
1158 return positionFromLineIndex( endLine, endIndex );
1159}
1160
1161void QgsCodeEditor::setLinearSelection( int start, int end )
1162{
1163 int startLine, startIndex, endLine, endIndex;
1164 lineIndexFromPosition( start, &startLine, &startIndex );
1165 lineIndexFromPosition( end, &endLine, &endIndex );
1166 setSelection( startLine, startIndex, endLine, endIndex );
1167}
1168
1170
1171int QgsCodeInterpreter::exec( const QString &command )
1172{
1173 mState = execCommandImpl( command );
1174 return mState;
1175}
MessageLevel
Level for messages This will be used both for message log and message bar in application.
Definition qgis.h:99
@ NoLevel
No level.
Definition qgis.h:104
@ Warning
Warning message.
Definition qgis.h:101
@ Critical
Critical/error message.
Definition qgis.h:102
@ Info
Information message.
Definition qgis.h:100
@ Success
Used for reporting a successful operation.
Definition qgis.h:103
@ CheckSyntax
Language supports syntax checking.
@ Reformat
Language supports automatic code reformatting.
@ ToggleComment
Language supports comment toggling.
ScriptLanguage
Scripting languages.
Definition qgis.h:3889
@ QgisExpression
QGIS expressions.
@ Batch
Windows batch files.
@ JavaScript
JavaScript.
@ Bash
Bash scripts.
@ Unknown
Unknown/other language.
QFlags< ScriptLanguageCapability > ScriptLanguageCapabilities
Script language capabilities.
Definition qgis.h:3924
static QPixmap getThemePixmap(const QString &name, const QColor &foreColor=QColor(), const QColor &backColor=QColor(), int size=16)
Helper to get a theme icon as a pixmap.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QHash< QString, QString > uiThemes()
All themes found in ~/.qgis3/themes folder.
static QString themeName()
Set the active theme to the specified theme.
QgsCodeEditorColorScheme scheme(const QString &id) const
Returns the color scheme with matching id.
Defines a color scheme for use in QgsCodeEditor widgets.
@ TripleSingleQuote
Triple single quote color.
@ CommentBlock
Comment block color.
@ QuotedOperator
Quoted operator color.
@ DoubleQuote
Double quote color.
@ QuotedIdentifier
Quoted identifier color.
@ SelectionForeground
Selection foreground color.
@ CommentLine
Line comment color.
@ FoldIconForeground
Fold icon foreground color.
@ MarginForeground
Margin foreground color.
@ ErrorBackground
Error background color.
@ MatchedBraceBackground
Matched brace background color.
@ SearchMatchBackground
Background color for search matches (since QGIS 3.38)
@ IndentationGuide
Indentation guide line.
@ SingleQuote
Single quote color.
@ MarginBackground
Margin background color.
@ SelectionBackground
Selection background color.
@ MatchedBraceForeground
Matched brace foreground color.
@ TripleDoubleQuote
Triple double quote color.
@ FoldIconHalo
Fold icon halo color.
QColor color(ColorRole role) const
Returns the color to use in the editor for the specified role.
A dialog for displaying and managing command history for a QgsCodeEditor widget.
bool eventFilter(QObject *watched, QEvent *event) override
void sessionHistoryCleared()
Emitted when the history of commands run in the current session is cleared.
void showHistory()
Shows the command history dialog.
void setCustomAppearance(const QString &scheme=QString(), const QMap< QgsCodeEditorColorScheme::ColorRole, QColor > &customColors=QMap< QgsCodeEditorColorScheme::ColorRole, QColor >(), const QString &fontFamily=QString(), int fontSize=0)
Sets a custom appearance for the widget, disconnecting it from using the standard appearance taken fr...
Mode
Code editor modes.
@ OutputDisplay
Read only mode for display of command outputs.
@ ScriptEditor
Standard mode, allows for display and edit of entire scripts.
@ CommandInput
Command input mode.
void reformatCode()
Applies code reformatting to the editor.
virtual void toggleComment()
Toggle comment for the selected text.
void contextMenuEvent(QContextMenuEvent *event) override
void clearPersistentHistory()
Clears the entire persistent history of commands run in the editor.
void removeHistoryCommand(int index)
Removes the command at the specified index from the history of the code editor.
static void setColor(QgsCodeEditorColorScheme::ColorRole role, const QColor &color)
Sets the color to use in the editor for the specified role.
void setHistoryFilePath(const QString &path)
Sets the file path to use for recording and retrieving previously executed commands.
void setLinearSelection(int start, int end)
Convenience function to set the selection using linear indexes.
QStringList history() const
Returns the list of commands previously executed in the editor.
static constexpr int SEARCH_RESULT_INDICATOR
Indicator index for search results.
void keyPressEvent(QKeyEvent *event) override
virtual void moveCursorToStart()
Moves the cursor to the start of the document and scrolls to ensure it is visible.
virtual void populateContextMenu(QMenu *menu)
Called when the context menu for the widget is about to be shown, after it has been fully populated w...
QFlags< Flag > Flags
Flags controlling behavior of code editor.
void persistentHistoryCleared()
Emitted when the persistent history of commands run in the editor is cleared.
void runCommand(const QString &command, bool skipHistory=false)
Runs a command in the editor.
void setFoldingVisible(bool folding)
Set whether the folding controls are visible in the editor.
virtual Qgis::ScriptLanguageCapabilities languageCapabilities() const
Returns the associated scripting language capabilities.
void setInterpreter(QgsCodeInterpreter *newInterpreter)
Sets an attached code interpreter for executing commands when the editor is in the QgsCodeEditor::Mod...
@ FoldingControls
Folding controls.
@ ErrorIndicators
Error indicators.
@ LineNumbers
Line numbers.
void runPostLexerConfigurationTasks()
Performs tasks which must be run after a lexer has been set for the widget.
virtual void showMessage(const QString &title, const QString &message, Qgis::MessageLevel level)
Shows a user facing message (eg a warning message).
int selectionEnd() const
Convenience function to return the end of the selection as a linear index Contrary to the getSelectio...
virtual void initializeLexer()
Called when the dialect specific code lexer needs to be initialized (or reinitialized).
int linearPosition() const
Convenience function to return the cursor position as a linear index.
void setTitle(const QString &title)
Set the widget title.
void setLinearPosition(int position)
Convenience function to set the cursor position as a linear index.
QgsCodeEditor(QWidget *parent=nullptr, const QString &title=QString(), bool folding=false, bool margin=false, QgsCodeEditor::Flags flags=QgsCodeEditor::Flags(), QgsCodeEditor::Mode mode=QgsCodeEditor::Mode::ScriptEditor)
Construct a new code editor.
void clearWarnings()
Clears all warning messages from the editor.
static QFont getMonospaceFont()
Returns the monospaced font to use for code editors.
void showNextCommand()
Shows the next command from the session in the editor.
void focusOutEvent(QFocusEvent *event) override
@ CodeFolding
Indicates that code folding should be enabled for the editor.
@ ImmediatelyUpdateHistory
Indicates that the history file should be immediately updated whenever a command is executed,...
bool isCursorOnLastLine() const
Returns true if the cursor is on the last line of the document.
static bool isFixedPitch(const QFont &font)
Returns true if a font is a fixed pitch font.
void updateSoftHistory()
Updates the soft history by storing the current editor text in the history.
void clearSessionHistory()
Clears the history of commands run in the current session.
void insertText(const QString &text)
Insert text at cursor position, or replace any selected text if user has made a selection.
bool writeHistoryFile()
Stores the commands executed in the editor to the persistent history file.
virtual void moveCursorToEnd()
Moves the cursor to the end of the document and scrolls to ensure it is visible.
static QString languageToString(Qgis::ScriptLanguage language)
Returns a user-friendly, translated name of the specified script language.
void setLineNumbersVisible(bool visible)
Sets whether line numbers should be visible in the editor.
virtual Qgis::ScriptLanguage language() const
Returns the associated scripting language.
QFont lexerFont() const
Returns the font to use in the lexer.
virtual QString reformatCodeString(const QString &string)
Applies code reformatting to a string and returns the result.
QgsCodeInterpreter * interpreter() const
Returns the attached code interpreter, or nullptr if not set.
bool lineNumbersVisible() const
Returns whether line numbers are visible in the editor.
QColor lexerColor(QgsCodeEditorColorScheme::ColorRole role) const
Returns the color to use in the lexer for the specified role.
bool foldingVisible()
Returns true if the folding controls are visible in the editor.
void showPreviousCommand()
Shows the previous command from the session in the editor.
Q_DECL_DEPRECATED void setMarginVisible(bool margin)
Set margin visible state.
void updatePrompt()
Triggers an update of the interactive prompt part of the editor.
static QColor defaultColor(QgsCodeEditorColorScheme::ColorRole role, const QString &theme=QString())
Returns the default color for the specified role.
int selectionStart() const
Convenience function to return the start of the selection as a linear index Contrary to the getSelect...
void addWarning(int lineNumber, const QString &warning)
Adds a warning message and indicator to the specified a lineNumber.
virtual bool checkSyntax()
Applies syntax checking to the editor.
static QColor color(QgsCodeEditorColorScheme::ColorRole role)
Returns the color to use in the editor for the specified role.
An interface for code interpreters.
virtual int execCommandImpl(const QString &command)=0
Pure virtual method for executing commands in the interpreter.
virtual int currentState() const
Returns the current interpreter state.
virtual QString promptForState(int state) const =0
Returns the interactive prompt string to use for the interpreter, given a state.
int exec(const QString &command)
Executes a command in the interpreter.
virtual ~QgsCodeInterpreter()
static void setFontFamily(QFont &font, const QString &family)
Sets the family for a font object.
void optionsChanged()
This signal is emitted whenever the application options have been changed.
static QgsGui * instance()
Returns a pointer to the singleton instance.
Definition qgsgui.cpp:73
static QgsCodeEditorColorSchemeRegistry * codeEditorColorSchemeRegistry()
Returns the global code editor color scheme registry, used for registering the color schemes for QgsC...
Definition qgsgui.cpp:154
This class is a composition of two QSettings instances:
Definition qgssettings.h:64
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void remove(const QString &key, QgsSettings::Section section=QgsSettings::NoSection)
Removes the setting key and any sub-settings of key in a section.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static int levenshteinDistance(const QString &string1, const QString &string2, bool caseSensitive=false)
Returns the Levenshtein edit distance between two strings.
static QColor decodeColor(const QString &str)
#define BUILTIN_UNREACHABLE
Definition qgis.h:6119
int findMinimalDistanceIndex(const QString &source, const QString &target)