QGIS API Documentation 3.37.0-Master (684a802617f)
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
79
80QgsCodeEditor::QgsCodeEditor( QWidget *parent, const QString &title, bool folding, bool margin, QgsCodeEditor::Flags flags, QgsCodeEditor::Mode mode )
81 : QsciScintilla( parent )
82 , mWidgetTitle( title )
83 , mMargin( margin )
84 , mFlags( flags )
85 , mMode( mode )
86{
87 if ( !parent && mWidgetTitle.isEmpty() )
88 {
89 setWindowTitle( QStringLiteral( "Text Editor" ) );
90 }
91 else
92 {
93 setWindowTitle( mWidgetTitle );
94 }
95
96 if ( folding )
98
99 mSoftHistory.append( QString() );
100
101 setSciWidget();
102 setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
103
104 SendScintilla( SCI_SETADDITIONALSELECTIONTYPING, 1 );
105 SendScintilla( SCI_SETMULTIPASTE, 1 );
106 SendScintilla( SCI_SETVIRTUALSPACEOPTIONS, SCVS_RECTANGULARSELECTION );
107
108 SendScintilla( SCI_SETMARGINTYPEN, static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), SC_MARGIN_SYMBOL );
109 SendScintilla( SCI_SETMARGINMASKN, static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 1 << MARKER_NUMBER );
110 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 0 );
111 setAnnotationDisplay( QsciScintilla::AnnotationBoxed );
112
113 connect( QgsGui::instance(), &QgsGui::optionsChanged, this, [ = ]
114 {
115 setSciWidget();
117 } );
118
119 switch ( mMode )
120 {
122 break;
123
125 {
126 // Don't want to see the horizontal scrollbar at all
127 SendScintilla( QsciScintilla::SCI_SETHSCROLLBAR, 0 );
128
129 setWrapMode( QsciScintilla::WrapCharacter );
130 break;
131 }
132
134 {
135 // Don't want to see the horizontal scrollbar at all
136 SendScintilla( QsciScintilla::SCI_SETHSCROLLBAR, 0 );
137
138 setWrapMode( QsciScintilla::WrapCharacter );
139 SendScintilla( QsciScintilla::SCI_EMPTYUNDOBUFFER );
140 break;
141 }
142 }
143
144#if QSCINTILLA_VERSION < 0x020d03
145 installEventFilter( this );
146#endif
147}
148
149// Workaround a bug in QScintilla 2.8.X
150void QgsCodeEditor::focusOutEvent( QFocusEvent *event )
151{
152#if QSCINTILLA_VERSION >= 0x020800 && QSCINTILLA_VERSION < 0x020900
153 if ( event->reason() != Qt::ActiveWindowFocusReason )
154 {
155 /* There's a bug in all QScintilla 2.8.X, where
156 a focus out event that is not due to ActiveWindowFocusReason doesn't
157 lead to the bliking caret being disabled. The hack consists in making
158 QsciScintilla::focusOutEvent believe that the event is a ActiveWindowFocusReason
159 The bug was fixed in 2.9 per:
160 2015-04-14 Phil Thompson <[email protected]>
161
162 * qt/qsciscintillabase.cpp:
163 Fixed a problem notifying when focus is lost to another application
164 widget.
165 [41734678234e]
166 */
167 QFocusEvent newFocusEvent( QEvent::FocusOut, Qt::ActiveWindowFocusReason );
168 QsciScintilla::focusOutEvent( &newFocusEvent );
169 }
170 else
171#endif
172 {
173 QsciScintilla::focusOutEvent( event );
174 }
175}
176
177// This workaround a likely bug in QScintilla. The ESC key should not be consumned
178// by the main entry, so that the default behavior (Dialog closing) can trigger,
179// but only is the auto-completion suggestion list isn't displayed
180void QgsCodeEditor::keyPressEvent( QKeyEvent *event )
181{
182 if ( isListActive() )
183 {
184 QsciScintilla::keyPressEvent( event );
185 return;
186 }
187
188 if ( event->key() == Qt::Key_Escape )
189 {
190 // Shortcut QScintilla and redirect the event to the QWidget handler
191 QWidget::keyPressEvent( event ); // NOLINT(bugprone-parent-virtual-call) clazy:exclude=skipped-base-method
192 return;
193 }
194
196 {
197 switch ( event->key() )
198 {
199 case Qt::Key_Return:
200 case Qt::Key_Enter:
201 runCommand( text() );
202 updatePrompt();
203 return;
204
205 case Qt::Key_Down:
207 updatePrompt();
208 return;
209
210 case Qt::Key_Up:
212 updatePrompt();
213 return;
214
215 default:
216 break;
217 }
218 }
219
220 const bool ctrlModifier = event->modifiers() & Qt::ControlModifier;
221 const bool altModifier = event->modifiers() & Qt::AltModifier;
222
223 // Ctrl+Alt+F: reformat code
225 if ( !isReadOnly() && canReformat && ctrlModifier && altModifier && event->key() == Qt::Key_F )
226 {
227 event->accept();
228 reformatCode();
229 return;
230 }
231
232 // Toggle comment when user presses Ctrl+:
234 if ( !isReadOnly() && canToggle && ctrlModifier && event->key() == Qt::Key_Colon )
235 {
236 event->accept();
238 return;
239 }
240
241 QsciScintilla::keyPressEvent( event );
242
243}
244
245void QgsCodeEditor::contextMenuEvent( QContextMenuEvent *event )
246{
247 switch ( mMode )
248 {
250 {
251 QMenu *menu = createStandardContextMenu();
252 menu->setAttribute( Qt::WA_DeleteOnClose );
253
256 {
257 menu->addSeparator();
258 }
259
261 {
262 QAction *reformatAction = new QAction( tr( "Reformat Code" ), menu );
263 reformatAction->setShortcut( QStringLiteral( "Ctrl+Alt+F" ) );
264 reformatAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconFormatCode.svg" ) ) );
265 reformatAction->setEnabled( !isReadOnly() );
266 connect( reformatAction, &QAction::triggered, this, &QgsCodeEditor::reformatCode );
267 menu->addAction( reformatAction );
268 }
269
271 {
272 QAction *syntaxCheckAction = new QAction( tr( "Check Syntax" ), menu );
273 syntaxCheckAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconSyntaxErrorConsole.svg" ) ) );
274 connect( syntaxCheckAction, &QAction::triggered, this, &QgsCodeEditor::checkSyntax );
275 menu->addAction( syntaxCheckAction );
276 }
277
279 {
280 QAction *toggleCommentAction = new QAction( tr( "Toggle Comment" ), menu );
281 toggleCommentAction->setShortcut( QStringLiteral( "Ctrl+:" ) );
282 toggleCommentAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "console/iconCommentEditorConsole.svg" ) ) );
283 toggleCommentAction->setEnabled( !isReadOnly() );
284 connect( toggleCommentAction, &QAction::triggered, this, &QgsCodeEditor::toggleComment );
285 menu->addAction( toggleCommentAction );
286 }
287
288 populateContextMenu( menu );
289
290 menu->exec( mapToGlobal( event->pos() ) );
291 break;
292 }
293
295 {
296 QMenu *menu = new QMenu( this );
297 QMenu *historySubMenu = new QMenu( tr( "Command History" ), menu );
298
299 historySubMenu->addAction( tr( "Show" ), this, &QgsCodeEditor::showHistory, QStringLiteral( "Ctrl+Shift+SPACE" ) );
300 historySubMenu->addAction( tr( "Clear File" ), this, &QgsCodeEditor::clearPersistentHistory );
301 historySubMenu->addAction( tr( "Clear Session" ), this, &QgsCodeEditor::clearSessionHistory );
302
303 menu->addMenu( historySubMenu );
304 menu->addSeparator();
305
306 QAction *copyAction = menu->addAction( QgsApplication::getThemeIcon( "mActionEditCopy.svg" ), tr( "Copy" ), this, &QgsCodeEditor::copy, QKeySequence::Copy );
307 QAction *pasteAction = menu->addAction( QgsApplication::getThemeIcon( "mActionEditPaste.svg" ), tr( "Paste" ), this, &QgsCodeEditor::paste, QKeySequence::Paste );
308 copyAction->setEnabled( hasSelectedText() );
309 pasteAction->setEnabled( !QApplication::clipboard()->text().isEmpty() );
310
311 populateContextMenu( menu );
312
313 menu->exec( mapToGlobal( event->pos() ) );
314 break;
315 }
316
318 QsciScintilla::contextMenuEvent( event );
319 break;
320 }
321}
322
323bool QgsCodeEditor::eventFilter( QObject *watched, QEvent *event )
324{
325#if QSCINTILLA_VERSION < 0x020d03
326 if ( watched == this && event->type() == QEvent::InputMethod )
327 {
328 // swallow input method events, which cause loss of selected text.
329 // See https://sourceforge.net/p/scintilla/bugs/1913/ , which was ported to QScintilla
330 // in version 2.13.3
331 return true;
332 }
333#endif
334
335 return QsciScintilla::eventFilter( watched, event );
336}
337
342
344{
345 if ( mUseDefaultSettings )
346 return color( role );
347
348 if ( !mOverrideColors )
349 {
350 return defaultColor( role, mColorScheme );
351 }
352 else
353 {
354 const QColor color = mCustomColors.value( role );
355 return !color.isValid() ? defaultColor( role ) : color;
356 }
357}
358
360{
361 if ( mUseDefaultSettings )
362 return getMonospaceFont();
363
364 QFont font = QFontDatabase::systemFont( QFontDatabase::FixedFont );
365
366 const QgsSettings settings;
367 if ( !mFontFamily.isEmpty() )
368 QgsFontUtils::setFontFamily( font, mFontFamily );
369
370#ifdef Q_OS_MAC
371 if ( mFontSize > 0 )
372 font.setPointSize( mFontSize );
373 else
374 {
375 // The font size gotten from getMonospaceFont() is too small on Mac
376 font.setPointSize( QLabel().font().pointSize() );
377 }
378#else
379 if ( mFontSize > 0 )
380 font.setPointSize( mFontSize );
381 else
382 {
383 const int fontSize = settings.value( QStringLiteral( "qgis/stylesheet/fontPointSize" ), 10 ).toInt();
384 font.setPointSize( fontSize );
385 }
386#endif
387 font.setBold( false );
388
389 return font;
390}
391
393{
394 updateFolding();
395
398
399 SendScintilla( SCI_MARKERSETFORE, SC_MARKNUM_FOLDEROPEN, lexerColor( QgsCodeEditorColorScheme::ColorRole::FoldIconHalo ) );
400 SendScintilla( SCI_MARKERSETBACK, SC_MARKNUM_FOLDEROPEN, lexerColor( QgsCodeEditorColorScheme::ColorRole::FoldIconForeground ) );
401 SendScintilla( SCI_MARKERSETFORE, SC_MARKNUM_FOLDER, lexerColor( QgsCodeEditorColorScheme::ColorRole::FoldIconHalo ) );
402 SendScintilla( SCI_MARKERSETBACK, SC_MARKNUM_FOLDER, lexerColor( QgsCodeEditorColorScheme::ColorRole::FoldIconForeground ) );
403 SendScintilla( SCI_STYLESETFORE, STYLE_INDENTGUIDE, lexerColor( QgsCodeEditorColorScheme::ColorRole::IndentationGuide ) );
404 SendScintilla( SCI_STYLESETBACK, STYLE_INDENTGUIDE, lexerColor( QgsCodeEditorColorScheme::ColorRole::IndentationGuide ) );
405
406 SendScintilla( QsciScintilla::SCI_INDICSETSTYLE, SEARCH_RESULT_INDICATOR, QsciScintilla::INDIC_STRAIGHTBOX );
407 SendScintilla( QsciScintilla::SCI_INDICSETFORE, SEARCH_RESULT_INDICATOR, lexerColor( QgsCodeEditorColorScheme::ColorRole::SearchMatchBackground ) );
408 SendScintilla( QsciScintilla::SCI_INDICSETALPHA, SEARCH_RESULT_INDICATOR, 100 );
409 SendScintilla( QsciScintilla::SCI_INDICSETUNDER, SEARCH_RESULT_INDICATOR, true );
410 SendScintilla( QsciScintilla::SCI_INDICGETOUTLINEALPHA, SEARCH_RESULT_INDICATOR, 255 );
411
413 {
414 setCaretLineVisible( false );
415 setLineNumbersVisible( false ); // NO linenumbers for the input line
416 // Margin 1 is used for the '>' prompt (console input)
417 setMarginLineNumbers( 1, true );
418 setMarginWidth( 1, "00000" );
419 setMarginType( 1, QsciScintilla::MarginType::TextMarginRightJustified );
420 setMarginsBackgroundColor( color( QgsCodeEditorColorScheme::ColorRole::Background ) );
421 setEdgeMode( QsciScintilla::EdgeNone );
422 }
423}
424
425void QgsCodeEditor::setSciWidget()
426{
427 const QFont font = lexerFont();
428 setFont( font );
429
430 setUtf8( true );
431 setCaretLineVisible( true );
432 setCaretLineBackgroundColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::CaretLine ) );
433 setCaretForegroundColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::Cursor ) );
436
437 setBraceMatching( QsciScintilla::SloppyBraceMatch );
440
441 setLineNumbersVisible( false );
442
443 // temporarily disable folding, will be enabled later if required by updateFolding()
444 setFolding( QsciScintilla::NoFoldStyle );
445 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::FoldingControls ), 0 );
446
447 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 0 );
448
451 setIndentationGuidesForegroundColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::MarginForeground ) );
452 setIndentationGuidesBackgroundColor( lexerColor( QgsCodeEditorColorScheme::ColorRole::MarginBackground ) );
453 // whether margin will be shown
454 updateFolding();
455 const QColor foldColor = lexerColor( QgsCodeEditorColorScheme::ColorRole::Fold );
456 setFoldMarginColors( foldColor, foldColor );
457 // indentation
458 setAutoIndent( true );
459 setIndentationWidth( 4 );
460 setTabIndents( true );
461 setBackspaceUnindents( true );
462 setTabWidth( 4 );
463 // autocomplete
464 setAutoCompletionThreshold( 2 );
465 setAutoCompletionSource( QsciScintilla::AcsAPIs );
466
467 markerDefine( QgsApplication::getThemePixmap( "console/iconSyntaxErrorConsoleParams.svg", lexerColor( QgsCodeEditorColorScheme::ColorRole::Error ),
469}
470
471void QgsCodeEditor::setTitle( const QString &title )
472{
473 setWindowTitle( title );
474}
475
480
485
487{
488 switch ( language )
489 {
491 return tr( "CSS" );
493 return tr( "Expression" );
495 return tr( "HTML" );
497 return tr( "JavaScript" );
499 return tr( "JSON" );
501 return tr( "Python" );
503 return tr( "R" );
505 return tr( "SQL" );
507 return tr( "Batch" );
509 return tr( "Bash" );
511 return QString();
512 }
514}
515
517{
518 mMargin = margin;
519 if ( margin )
520 {
521 QFont marginFont = lexerFont();
522 marginFont.setPointSize( 10 );
523 setMarginLineNumbers( 0, true );
524 setMarginsFont( marginFont );
525 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), QStringLiteral( "00000" ) );
528 }
529 else
530 {
531 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), 0 );
532 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 0 );
533 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::FoldingControls ), 0 );
534 }
535}
536
538{
539 if ( visible )
540 {
541 QFont marginFont = lexerFont();
542 marginFont.setPointSize( 10 );
543 setMarginLineNumbers( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), true );
544 setMarginsFont( marginFont );
545 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), QStringLiteral( "00000" ) );
548 }
549 else
550 {
551 setMarginLineNumbers( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), false );
552 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ), 0 );
553 }
554}
555
557{
558 return marginLineNumbers( static_cast< int >( QgsCodeEditor::MarginRole::LineNumbers ) );
559}
560
562{
563 if ( folding )
564 {
566 }
567 else
568 {
569 mFlags &= ~( static_cast< int >( QgsCodeEditor::Flag::CodeFolding ) );
570 }
571 updateFolding();
572}
573
578
579void QgsCodeEditor::updateFolding()
580{
582 {
583 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::FoldingControls ), "0" );
586 setFolding( QsciScintilla::PlainFoldStyle );
587 }
588 else
589 {
590 setFolding( QsciScintilla::NoFoldStyle );
591 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::FoldingControls ), 0 );
592 }
593}
594
595bool QgsCodeEditor::readHistoryFile()
596{
597 if ( mHistoryFilePath.isEmpty() || !QFile::exists( mHistoryFilePath ) )
598 return false;
599
600 QFile file( mHistoryFilePath );
601 if ( file.open( QIODevice::ReadOnly ) )
602 {
603 QTextStream stream( &file );
604#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
605 // Always use UTF-8
606 stream.setCodec( "UTF-8" );
607#endif
608 QString line;
609 while ( !stream.atEnd() )
610 {
611 line = stream.readLine(); // line of text excluding '\n'
612 mHistory.append( line );
613 }
614 syncSoftHistory();
615 return true;
616 }
617
618 return false;
619}
620
621void QgsCodeEditor::syncSoftHistory()
622{
623 mSoftHistory = mHistory;
624 mSoftHistory.append( QString() );
625 mSoftHistoryIndex = mSoftHistory.length() - 1;
626}
627
629{
630 mSoftHistory[mSoftHistoryIndex] = text();
631}
632
633void QgsCodeEditor::updateHistory( const QStringList &commands, bool skipSoftHistory )
634{
635 if ( commands.size() > 1 )
636 {
637 mHistory.append( commands );
638 }
639 else if ( !commands.value( 0 ).isEmpty() )
640 {
641 const QString command = commands.value( 0 );
642 if ( mHistory.empty() || command != mHistory.constLast() )
643 mHistory.append( command );
644 }
645
646 if ( !skipSoftHistory )
647 syncSoftHistory();
648}
649
651{
652
653}
654
655QString QgsCodeEditor::reformatCodeString( const QString &string )
656{
657 return string;
658}
659
660void QgsCodeEditor::showMessage( const QString &title, const QString &message, Qgis::MessageLevel level )
661{
662 switch ( level )
663 {
664 case Qgis::Info:
665 case Qgis::Success:
666 case Qgis::NoLevel:
667 QMessageBox::information( this, title, message );
668 break;
669
670 case Qgis::Warning:
671 QMessageBox::warning( this, title, message );
672 break;
673
674 case Qgis::Critical:
675 QMessageBox::critical( this, title, message );
676 break;
677 }
678}
679
681{
682 if ( mInterpreter )
683 {
684 const QString prompt = mInterpreter->promptForState( mInterpreter->currentState() );
685 SendScintilla( QsciScintilla::SCI_MARGINSETTEXT, static_cast< uintptr_t >( 0 ), prompt.toUtf8().constData() );
686 }
687}
688
690{
691 return mInterpreter;
692}
693
695{
696 mInterpreter = newInterpreter;
697 updatePrompt();
698}
699
700// Find the source substring index that most closely matches the target string
701int findMinimalDistanceIndex( const QString &source, const QString &target )
702{
703 const int index = std::min( source.length(), target.length() );
704
705 const int d0 = QgsStringUtils::levenshteinDistance( source.left( index ), target );
706 if ( d0 == 0 )
707 return index;
708
709 int refDistanceMore = d0;
710 int refIndexMore = index;
711 if ( index < source.length() - 1 )
712 {
713 while ( true )
714 {
715 const int newDistance = QgsStringUtils::levenshteinDistance( source.left( refIndexMore + 1 ), target );
716 if ( newDistance <= refDistanceMore )
717 {
718 refDistanceMore = newDistance;
719 refIndexMore++;
720 if ( refIndexMore == source.length() - 1 )
721 break;
722 }
723 else
724 {
725 break;
726 }
727 }
728 }
729
730 int refDistanceLess = d0;
731 int refIndexLess = index;
732 if ( index > 0 )
733 {
734 while ( true )
735 {
736 const int newDistance = QgsStringUtils::levenshteinDistance( source.left( refIndexLess - 1 ), target );
737 if ( newDistance <= refDistanceLess )
738 {
739 refDistanceLess = newDistance;
740 refIndexLess--;
741 if ( refIndexLess == 0 )
742 break;
743 }
744 else
745 {
746 break;
747 }
748 }
749 }
750
751 if ( refDistanceMore < refDistanceLess )
752 return refIndexMore;
753 else
754 return refIndexLess;
755}
756
758{
760 return;
761
762 const QString textBeforeCursor = text( 0, linearPosition() );
763 const QString originalText = text();
764 const QString newText = reformatCodeString( originalText );
765
766 if ( originalText == newText )
767 return;
768
769 // try to preserve the cursor position and scroll position
770 const int oldScrollValue = verticalScrollBar()->value();
771 const int linearIndex = findMinimalDistanceIndex( newText, textBeforeCursor );
772
773 beginUndoAction();
774 selectAll();
775 removeSelectedText();
776 insert( newText );
777 setLinearPosition( linearIndex );
778 verticalScrollBar()->setValue( oldScrollValue );
779 endUndoAction();
780}
781
783{
784 return true;
785}
786
788{
789
790}
791
792QStringList QgsCodeEditor::history() const
793{
794 return mHistory;
795}
796
797void QgsCodeEditor::runCommand( const QString &command, bool skipHistory )
798{
799 if ( !skipHistory )
800 {
801 updateHistory( { command } );
804 }
805
806 if ( mInterpreter )
807 mInterpreter->exec( command );
808
809 clear();
811}
812
814{
815 mHistory.clear();
816 readHistoryFile();
817 syncSoftHistory();
818
820}
821
823{
824 mHistory.clear();
825
826 if ( !mHistoryFilePath.isEmpty() && QFile::exists( mHistoryFilePath ) )
827 {
828 QFile file( mHistoryFilePath );
829 file.open( QFile::WriteOnly | QFile::Truncate );
830 }
831
833}
834
836{
837 if ( mHistoryFilePath.isEmpty() )
838 return false;
839
840 QFile f( mHistoryFilePath );
841 if ( !f.open( QFile::WriteOnly | QIODevice::Truncate ) )
842 {
843 return false;
844 }
845
846 QTextStream ts( &f );
847#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
848 ts.setCodec( "UTF-8" );
849#endif
850 for ( const QString &command : std::as_const( mHistory ) )
851 {
852 ts << command + '\n';
853 }
854 return true;
855}
856
858{
859 if ( mSoftHistoryIndex < mSoftHistory.length() - 1 && !mSoftHistory.isEmpty() )
860 {
861 mSoftHistoryIndex += 1;
862 setText( mSoftHistory[mSoftHistoryIndex] );
864 }
865}
866
868{
869 if ( mSoftHistoryIndex > 0 && !mSoftHistory.empty() )
870 {
871 mSoftHistoryIndex -= 1;
872 setText( mSoftHistory[mSoftHistoryIndex] );
874 }
875}
876
878{
879 QgsCodeEditorHistoryDialog *dialog = new QgsCodeEditorHistoryDialog( this, this );
880 dialog->setAttribute( Qt::WA_DeleteOnClose );
881
882 dialog->show();
883 dialog->activateWindow();
884}
885
887{
888 // remove item from the command history (just for the current session)
889 mHistory.removeAt( index );
890 mSoftHistory.removeAt( index );
891 if ( index < mSoftHistoryIndex )
892 {
893 mSoftHistoryIndex -= 1;
894 if ( mSoftHistoryIndex < 0 )
895 mSoftHistoryIndex = mSoftHistory.length() - 1;
896 }
897}
898
899void QgsCodeEditor::insertText( const QString &text )
900{
901 // Insert the text or replace selected text
902 if ( hasSelectedText() )
903 {
904 replaceSelectedText( text );
905 }
906 else
907 {
908 int line, index;
909 getCursorPosition( &line, &index );
910 insertAt( text, line, index );
911 setCursorPosition( line, index + text.length() );
912 }
913}
914
916{
917 if ( theme.isEmpty() && QgsApplication::themeName() == QLatin1String( "default" ) )
918 {
919 // if using default theme, take certain colors from the palette
920 const QPalette pal = qApp->palette();
921
922 switch ( role )
923 {
925 return pal.color( QPalette::Highlight );
927 return pal.color( QPalette::HighlightedText );
928 default:
929 break;
930 }
931 }
932 else if ( theme.isEmpty() )
933 {
934 // non default theme (e.g. Blend of Gray). Take colors from theme ini file...
935 const QSettings ini( QgsApplication::uiThemes().value( QgsApplication::themeName() ) + "/qscintilla.ini", QSettings::IniFormat );
936
937 static const QMap< QgsCodeEditorColorScheme::ColorRole, QString > sColorRoleToIniKey
938 {
939 {QgsCodeEditorColorScheme::ColorRole::Default, QStringLiteral( "python/defaultFontColor" ) },
940 {QgsCodeEditorColorScheme::ColorRole::Keyword, QStringLiteral( "python/keywordFontColor" ) },
941 {QgsCodeEditorColorScheme::ColorRole::Class, QStringLiteral( "python/classFontColor" ) },
942 {QgsCodeEditorColorScheme::ColorRole::Method, QStringLiteral( "python/methodFontColor" ) },
943 {QgsCodeEditorColorScheme::ColorRole::Decoration, QStringLiteral( "python/decoratorFontColor" ) },
944 {QgsCodeEditorColorScheme::ColorRole::Number, QStringLiteral( "python/numberFontColor" ) },
945 {QgsCodeEditorColorScheme::ColorRole::Comment, QStringLiteral( "python/commentFontColor" ) },
946 {QgsCodeEditorColorScheme::ColorRole::CommentLine, QStringLiteral( "sql/commentLineFontColor" ) },
947 {QgsCodeEditorColorScheme::ColorRole::CommentBlock, QStringLiteral( "python/commentBlockFontColor" ) },
948 {QgsCodeEditorColorScheme::ColorRole::Background, QStringLiteral( "python/paperBackgroundColor" ) },
949 {QgsCodeEditorColorScheme::ColorRole::Cursor, QStringLiteral( "cursorColor" ) },
950 {QgsCodeEditorColorScheme::ColorRole::CaretLine, QStringLiteral( "caretLineColor" ) },
951 {QgsCodeEditorColorScheme::ColorRole::Operator, QStringLiteral( "sql/operatorFontColor" ) },
952 {QgsCodeEditorColorScheme::ColorRole::QuotedOperator, QStringLiteral( "sql/QuotedOperatorFontColor" ) },
953 {QgsCodeEditorColorScheme::ColorRole::Identifier, QStringLiteral( "sql/identifierFontColor" ) },
954 {QgsCodeEditorColorScheme::ColorRole::QuotedIdentifier, QStringLiteral( "sql/QuotedIdentifierFontColor" ) },
955 {QgsCodeEditorColorScheme::ColorRole::Tag, QStringLiteral( "html/tagFontColor" ) },
956 {QgsCodeEditorColorScheme::ColorRole::UnknownTag, QStringLiteral( "html/unknownTagFontColor" ) },
957 {QgsCodeEditorColorScheme::ColorRole::SingleQuote, QStringLiteral( "sql/singleQuoteFontColor" ) },
958 {QgsCodeEditorColorScheme::ColorRole::DoubleQuote, QStringLiteral( "sql/doubleQuoteFontColor" ) },
959 {QgsCodeEditorColorScheme::ColorRole::TripleSingleQuote, QStringLiteral( "python/tripleSingleQuoteFontColor" ) },
960 {QgsCodeEditorColorScheme::ColorRole::TripleDoubleQuote, QStringLiteral( "python/tripleDoubleQuoteFontColor" ) },
961 {QgsCodeEditorColorScheme::ColorRole::MarginBackground, QStringLiteral( "marginBackgroundColor" ) },
962 {QgsCodeEditorColorScheme::ColorRole::MarginForeground, QStringLiteral( "marginForegroundColor" ) },
963 {QgsCodeEditorColorScheme::ColorRole::SelectionBackground, QStringLiteral( "selectionBackgroundColor" ) },
964 {QgsCodeEditorColorScheme::ColorRole::SelectionForeground, QStringLiteral( "selectionForegroundColor" ) },
965 {QgsCodeEditorColorScheme::ColorRole::MatchedBraceBackground, QStringLiteral( "matchedBraceBackground" ) },
966 {QgsCodeEditorColorScheme::ColorRole::MatchedBraceForeground, QStringLiteral( "matchedBraceColor" ) },
967 {QgsCodeEditorColorScheme::ColorRole::Edge, QStringLiteral( "edgeColor" ) },
968 {QgsCodeEditorColorScheme::ColorRole::Fold, QStringLiteral( "foldColor" ) },
969 {QgsCodeEditorColorScheme::ColorRole::Error, QStringLiteral( "stderrFontColor" ) },
970 {QgsCodeEditorColorScheme::ColorRole::ErrorBackground, QStringLiteral( "stderrBackground" ) },
971 {QgsCodeEditorColorScheme::ColorRole::FoldIconForeground, QStringLiteral( "foldIconForeground" ) },
972 {QgsCodeEditorColorScheme::ColorRole::FoldIconHalo, QStringLiteral( "foldIconHalo" ) },
973 {QgsCodeEditorColorScheme::ColorRole::IndentationGuide, QStringLiteral( "indentationGuide" ) },
974 {QgsCodeEditorColorScheme::ColorRole::SearchMatchBackground, QStringLiteral( "searchMatchBackground" ) },
975 };
976
977 const QgsCodeEditorColorScheme defaultScheme = QgsGui::codeEditorColorSchemeRegistry()->scheme( QStringLiteral( "default" ) );
978 return QgsSymbolLayerUtils::decodeColor( ini.value( sColorRoleToIniKey.value( role ), defaultScheme.color( role ).name() ).toString() );
979 }
980
981 const QgsCodeEditorColorScheme scheme = QgsGui::codeEditorColorSchemeRegistry()->scheme( theme.isEmpty() ? QStringLiteral( "default" ) : theme );
982 return scheme.color( role );
983}
984
986{
987 const QgsSettings settings;
988 if ( !settings.value( QStringLiteral( "codeEditor/overrideColors" ), false, QgsSettings::Gui ).toBool() )
989 {
990 const QString theme = settings.value( QStringLiteral( "codeEditor/colorScheme" ), QString(), QgsSettings::Gui ).toString();
991 return defaultColor( role, theme );
992 }
993 else
994 {
995 const QString color = settings.value( QStringLiteral( "codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), QString(), QgsSettings::Gui ).toString();
996 return color.isEmpty() ? defaultColor( role ) : QgsSymbolLayerUtils::decodeColor( color );
997 }
998}
999
1001{
1002 QgsSettings settings;
1003 if ( color.isValid() )
1004 {
1005 settings.setValue( QStringLiteral( "codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), color.name(), QgsSettings::Gui );
1006 }
1007 else
1008 {
1009 settings.remove( QStringLiteral( "codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), QgsSettings::Gui );
1010 }
1011}
1012
1013// Settings for font and fontsize
1014bool QgsCodeEditor::isFixedPitch( const QFont &font )
1015{
1016 return font.fixedPitch();
1017}
1018
1020{
1021 QFont font = QFontDatabase::systemFont( QFontDatabase::FixedFont );
1022
1023 const QgsSettings settings;
1024 if ( !settings.value( QStringLiteral( "codeEditor/fontfamily" ), QString(), QgsSettings::Gui ).toString().isEmpty() )
1025 QgsFontUtils::setFontFamily( font, settings.value( QStringLiteral( "codeEditor/fontfamily" ), QString(), QgsSettings::Gui ).toString() );
1026
1027 const int fontSize = settings.value( QStringLiteral( "codeEditor/fontsize" ), 0, QgsSettings::Gui ).toInt();
1028
1029#ifdef Q_OS_MAC
1030 if ( fontSize > 0 )
1031 font.setPointSize( fontSize );
1032 else
1033 {
1034 // The font size gotten from getMonospaceFont() is too small on Mac
1035 font.setPointSize( QLabel().font().pointSize() );
1036 }
1037#else
1038 if ( fontSize > 0 )
1039 font.setPointSize( fontSize );
1040 else
1041 {
1042 const int fontSize = settings.value( QStringLiteral( "qgis/stylesheet/fontPointSize" ), 10 ).toInt();
1043 font.setPointSize( fontSize );
1044 }
1045#endif
1046 font.setBold( false );
1047
1048 return font;
1049}
1050
1051void QgsCodeEditor::setCustomAppearance( const QString &scheme, const QMap<QgsCodeEditorColorScheme::ColorRole, QColor> &customColors, const QString &fontFamily, int fontSize )
1052{
1053 mUseDefaultSettings = false;
1054 mOverrideColors = !customColors.isEmpty();
1055 mColorScheme = scheme;
1056 mCustomColors = customColors;
1057 mFontFamily = fontFamily;
1058 mFontSize = fontSize;
1059
1060 setSciWidget();
1062}
1063
1064void QgsCodeEditor::addWarning( const int lineNumber, const QString &warning )
1065{
1066 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), "000" );
1067 markerAdd( lineNumber, MARKER_NUMBER );
1068 QFont font = lexerFont();
1069 font.setItalic( true );
1070 const QsciStyle styleAnn = QsciStyle( -1, QStringLiteral( "Annotation" ),
1073 font,
1074 true );
1075 annotate( lineNumber, warning, styleAnn );
1076 mWarningLines.push_back( lineNumber );
1077}
1078
1080{
1081 for ( const int line : mWarningLines )
1082 {
1083 markerDelete( line );
1084 clearAnnotations( line );
1085 }
1086 setMarginWidth( static_cast< int >( QgsCodeEditor::MarginRole::ErrorIndicators ), 0 );
1087 mWarningLines.clear();
1088}
1089
1091{
1092 int line = 0;
1093 int index = 0;
1094 getCursorPosition( &line, &index );
1095 return line == lines() - 1;
1096}
1097
1098void QgsCodeEditor::setHistoryFilePath( const QString &path )
1099{
1100 mHistoryFilePath = path;
1101 readHistoryFile();
1102}
1103
1105{
1106 setCursorPosition( 0, 0 );
1107 ensureCursorVisible();
1108 ensureLineVisible( 0 );
1109
1110 if ( mMode == QgsCodeEditor::Mode::CommandInput )
1111 updatePrompt();
1112}
1113
1115{
1116 const int endLine = lines() - 1;
1117 const int endLineLength = lineLength( endLine );
1118 setCursorPosition( endLine, endLineLength );
1119 ensureCursorVisible();
1120 ensureLineVisible( endLine );
1121
1122 if ( mMode == QgsCodeEditor::Mode::CommandInput )
1123 updatePrompt();
1124}
1125
1127{
1128 int line, index;
1129 getCursorPosition( &line, &index );
1130 return positionFromLineIndex( line, index );
1131}
1132
1134{
1135 int line, index;
1136 lineIndexFromPosition( linearIndex, &line, &index );
1137 setCursorPosition( line, index );
1138}
1139
1141{
1142 int startLine, startIndex, _;
1143 getSelection( &startLine, &startIndex, &_, &_ );
1144 if ( startLine == -1 )
1145 {
1146 return linearPosition();
1147 }
1148 return positionFromLineIndex( startLine, startIndex );
1149}
1150
1152{
1153 int endLine, endIndex, _;
1154 getSelection( &_, &_, &endLine, &endIndex );
1155 if ( endLine == -1 )
1156 {
1157 return linearPosition();
1158 }
1159 return positionFromLineIndex( endLine, endIndex );
1160}
1161
1162void QgsCodeEditor::setLinearSelection( int start, int end )
1163{
1164 int startLine, startIndex, endLine, endIndex;
1165 lineIndexFromPosition( start, &startLine, &startIndex );
1166 lineIndexFromPosition( end, &endLine, &endIndex );
1167 setSelection( startLine, startIndex, endLine, endIndex );
1168}
1169
1171
1172int QgsCodeInterpreter::exec( const QString &command )
1173{
1174 mState = execCommandImpl( command );
1175 return mState;
1176}
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:3884
@ 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:3919
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:6099
int findMinimalDistanceIndex(const QString &source, const QString &target)