30#include <QFontDatabase>
33#include <Qsci/qscistyle.h>
39QMap< QgsCodeEditorColorScheme::ColorRole, QString > QgsCodeEditor::sColorRoleToSettingsKey
81 : QsciScintilla( parent )
82 , mWidgetTitle( title )
87 if ( !parent && mWidgetTitle.isEmpty() )
89 setWindowTitle( QStringLiteral(
"Text Editor" ) );
93 setWindowTitle( mWidgetTitle );
99 mSoftHistory.append( QString() );
102 setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
104 SendScintilla( SCI_SETADDITIONALSELECTIONTYPING, 1 );
105 SendScintilla( SCI_SETMULTIPASTE, 1 );
106 SendScintilla( SCI_SETVIRTUALSPACEOPTIONS, SCVS_RECTANGULARSELECTION );
111 setAnnotationDisplay( QsciScintilla::AnnotationBoxed );
127 SendScintilla( QsciScintilla::SCI_SETHSCROLLBAR, 0 );
129 setWrapMode( QsciScintilla::WrapCharacter );
136 SendScintilla( QsciScintilla::SCI_SETHSCROLLBAR, 0 );
138 setWrapMode( QsciScintilla::WrapCharacter );
139 SendScintilla( QsciScintilla::SCI_EMPTYUNDOBUFFER );
144#if QSCINTILLA_VERSION < 0x020d03
145 installEventFilter(
this );
152#if QSCINTILLA_VERSION >= 0x020800 && QSCINTILLA_VERSION < 0x020900
153 if ( event->reason() != Qt::ActiveWindowFocusReason )
167 QFocusEvent newFocusEvent( QEvent::FocusOut, Qt::ActiveWindowFocusReason );
168 QsciScintilla::focusOutEvent( &newFocusEvent );
173 QsciScintilla::focusOutEvent( event );
182 if ( isListActive() )
184 QsciScintilla::keyPressEvent( event );
188 if ( event->key() == Qt::Key_Escape )
191 QWidget::keyPressEvent( event );
197 switch ( event->key() )
220 const bool ctrlModifier =
event->modifiers() & Qt::ControlModifier;
221 const bool altModifier =
event->modifiers() & Qt::AltModifier;
225 if ( !isReadOnly() && canReformat && ctrlModifier && altModifier && event->key() == Qt::Key_F )
234 if ( !isReadOnly() && canToggle && ctrlModifier && event->key() == Qt::Key_Colon )
241 QsciScintilla::keyPressEvent( event );
251 QMenu *menu = createStandardContextMenu();
252 menu->setAttribute( Qt::WA_DeleteOnClose );
257 menu->addSeparator();
262 QAction *reformatAction =
new QAction( tr(
"Reformat Code" ), menu );
263 reformatAction->setShortcut( QStringLiteral(
"Ctrl+Alt+F" ) );
265 reformatAction->setEnabled( !isReadOnly() );
267 menu->addAction( reformatAction );
272 QAction *syntaxCheckAction =
new QAction( tr(
"Check Syntax" ), menu );
275 menu->addAction( syntaxCheckAction );
280 QAction *toggleCommentAction =
new QAction( tr(
"Toggle Comment" ), menu );
281 toggleCommentAction->setShortcut( QStringLiteral(
"Ctrl+:" ) );
283 toggleCommentAction->setEnabled( !isReadOnly() );
285 menu->addAction( toggleCommentAction );
290 menu->exec( mapToGlobal( event->pos() ) );
296 QMenu *menu =
new QMenu(
this );
297 QMenu *historySubMenu =
new QMenu( tr(
"Command History" ), menu );
303 menu->addMenu( historySubMenu );
304 menu->addSeparator();
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() );
313 menu->exec( mapToGlobal( event->pos() ) );
318 QsciScintilla::contextMenuEvent( event );
325#if QSCINTILLA_VERSION < 0x020d03
326 if ( watched ==
this && event->type() == QEvent::InputMethod )
335 return QsciScintilla::eventFilter( watched, event );
345 if ( mUseDefaultSettings )
346 return color( role );
348 if ( !mOverrideColors )
354 const QColor
color = mCustomColors.value( role );
361 if ( mUseDefaultSettings )
364 QFont font = QFontDatabase::systemFont( QFontDatabase::FixedFont );
367 if ( !mFontFamily.isEmpty() )
372 font.setPointSize( mFontSize );
376 font.setPointSize( QLabel().font().pointSize() );
380 font.setPointSize( mFontSize );
383 const int fontSize = settings.
value( QStringLiteral(
"qgis/stylesheet/fontPointSize" ), 10 ).toInt();
384 font.setPointSize( fontSize );
387 font.setBold(
false );
414 setCaretLineVisible(
false );
417 setMarginLineNumbers( 1,
true );
418 setMarginWidth( 1,
"00000" );
419 setMarginType( 1, QsciScintilla::MarginType::TextMarginRightJustified );
421 setEdgeMode( QsciScintilla::EdgeNone );
425void QgsCodeEditor::setSciWidget()
431 setCaretLineVisible(
true );
437 setBraceMatching( QsciScintilla::SloppyBraceMatch );
444 setFolding( QsciScintilla::NoFoldStyle );
456 setFoldMarginColors( foldColor, foldColor );
458 setAutoIndent(
true );
459 setIndentationWidth( 4 );
460 setTabIndents(
true );
461 setBackspaceUnindents(
true );
464 setAutoCompletionThreshold( 2 );
465 setAutoCompletionSource( QsciScintilla::AcsAPIs );
473 setWindowTitle( title );
493 return tr(
"Expression" );
497 return tr(
"JavaScript" );
501 return tr(
"Python" );
507 return tr(
"Batch" );
522 marginFont.setPointSize( 10 );
523 setMarginLineNumbers( 0,
true );
524 setMarginsFont( marginFont );
542 marginFont.setPointSize( 10 );
544 setMarginsFont( marginFont );
579void QgsCodeEditor::updateFolding()
586 setFolding( QsciScintilla::PlainFoldStyle );
590 setFolding( QsciScintilla::NoFoldStyle );
595bool QgsCodeEditor::readHistoryFile()
597 if ( mHistoryFilePath.isEmpty() || !QFile::exists( mHistoryFilePath ) )
600 QFile file( mHistoryFilePath );
601 if ( file.open( QIODevice::ReadOnly ) )
603 QTextStream stream( &file );
604#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
606 stream.setCodec(
"UTF-8" );
609 while ( !stream.atEnd() )
611 line = stream.readLine();
612 mHistory.append( line );
621void QgsCodeEditor::syncSoftHistory()
623 mSoftHistory = mHistory;
624 mSoftHistory.append( QString() );
625 mSoftHistoryIndex = mSoftHistory.length() - 1;
630 mSoftHistory[mSoftHistoryIndex] = text();
633void QgsCodeEditor::updateHistory(
const QStringList &commands,
bool skipSoftHistory )
635 if ( commands.size() > 1 )
637 mHistory.append( commands );
639 else if ( !commands.value( 0 ).isEmpty() )
641 const QString command = commands.value( 0 );
642 if ( mHistory.empty() || command != mHistory.constLast() )
643 mHistory.append( command );
646 if ( !skipSoftHistory )
667 QMessageBox::information(
this, title, message );
671 QMessageBox::warning(
this, title, message );
675 QMessageBox::critical(
this, title, message );
685 SendScintilla( QsciScintilla::SCI_MARGINSETTEXT,
static_cast< uintptr_t
>( 0 ), prompt.toUtf8().constData() );
696 mInterpreter = newInterpreter;
703 const int index = std::min( source.length(), target.length() );
709 int refDistanceMore = d0;
710 int refIndexMore = index;
711 if ( index < source.length() - 1 )
716 if ( newDistance <= refDistanceMore )
718 refDistanceMore = newDistance;
720 if ( refIndexMore == source.length() - 1 )
730 int refDistanceLess = d0;
731 int refIndexLess = index;
737 if ( newDistance <= refDistanceLess )
739 refDistanceLess = newDistance;
741 if ( refIndexLess == 0 )
751 if ( refDistanceMore < refDistanceLess )
763 const QString originalText = text();
766 if ( originalText == newText )
770 const int oldScrollValue = verticalScrollBar()->value();
775 removeSelectedText();
778 verticalScrollBar()->setValue( oldScrollValue );
801 updateHistory( { command } );
807 mInterpreter->
exec( command );
826 if ( !mHistoryFilePath.isEmpty() && QFile::exists( mHistoryFilePath ) )
828 QFile file( mHistoryFilePath );
829 file.open( QFile::WriteOnly | QFile::Truncate );
837 if ( mHistoryFilePath.isEmpty() )
840 QFile f( mHistoryFilePath );
841 if ( !f.open( QFile::WriteOnly | QIODevice::Truncate ) )
846 QTextStream ts( &f );
847#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
848 ts.setCodec(
"UTF-8" );
850 for (
const QString &command : std::as_const( mHistory ) )
852 ts << command +
'\n';
859 if ( mSoftHistoryIndex < mSoftHistory.length() - 1 && !mSoftHistory.isEmpty() )
861 mSoftHistoryIndex += 1;
862 setText( mSoftHistory[mSoftHistoryIndex] );
869 if ( mSoftHistoryIndex > 0 && !mSoftHistory.empty() )
871 mSoftHistoryIndex -= 1;
872 setText( mSoftHistory[mSoftHistoryIndex] );
880 dialog->setAttribute( Qt::WA_DeleteOnClose );
883 dialog->activateWindow();
889 mHistory.removeAt( index );
890 mSoftHistory.removeAt( index );
891 if ( index < mSoftHistoryIndex )
893 mSoftHistoryIndex -= 1;
894 if ( mSoftHistoryIndex < 0 )
895 mSoftHistoryIndex = mSoftHistory.length() - 1;
902 if ( hasSelectedText() )
904 replaceSelectedText( text );
909 getCursorPosition( &line, &index );
910 insertAt( text, line, index );
911 setCursorPosition( line, index + text.length() );
920 const QPalette
pal = qApp->palette();
925 return pal.color( QPalette::Highlight );
927 return pal.color( QPalette::HighlightedText );
932 else if ( theme.isEmpty() )
937 static const QMap< QgsCodeEditorColorScheme::ColorRole, QString > sColorRoleToIniKey
982 return scheme.
color( role );
988 if ( !settings.
value( QStringLiteral(
"codeEditor/overrideColors" ),
false,
QgsSettings::Gui ).toBool() )
990 const QString theme = settings.
value( QStringLiteral(
"codeEditor/colorScheme" ), QString(),
QgsSettings::Gui ).toString();
995 const QString
color = settings.
value( QStringLiteral(
"codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ), QString(),
QgsSettings::Gui ).toString();
1003 if (
color.isValid() )
1009 settings.
remove( QStringLiteral(
"codeEditor/%1" ).arg( sColorRoleToSettingsKey.value( role ) ),
QgsSettings::Gui );
1016 return font.fixedPitch();
1021 QFont font = QFontDatabase::systemFont( QFontDatabase::FixedFont );
1024 if ( !settings.
value( QStringLiteral(
"codeEditor/fontfamily" ), QString(),
QgsSettings::Gui ).toString().isEmpty() )
1027 const int fontSize = settings.
value( QStringLiteral(
"codeEditor/fontsize" ), 0,
QgsSettings::Gui ).toInt();
1031 font.setPointSize( fontSize );
1035 font.setPointSize( QLabel().font().pointSize() );
1039 font.setPointSize( fontSize );
1042 const int fontSize = settings.
value( QStringLiteral(
"qgis/stylesheet/fontPointSize" ), 10 ).toInt();
1043 font.setPointSize( fontSize );
1046 font.setBold(
false );
1053 mUseDefaultSettings =
false;
1054 mOverrideColors = !customColors.isEmpty();
1055 mColorScheme = scheme;
1056 mCustomColors = customColors;
1057 mFontFamily = fontFamily;
1058 mFontSize = fontSize;
1067 markerAdd( lineNumber, MARKER_NUMBER );
1069 font.setItalic(
true );
1070 const QsciStyle styleAnn = QsciStyle( -1, QStringLiteral(
"Annotation" ),
1075 annotate( lineNumber, warning, styleAnn );
1076 mWarningLines.push_back( lineNumber );
1081 for (
const int line : mWarningLines )
1083 markerDelete( line );
1084 clearAnnotations( line );
1087 mWarningLines.clear();
1094 getCursorPosition( &line, &index );
1095 return line == lines() - 1;
1100 mHistoryFilePath = path;
1106 setCursorPosition( 0, 0 );
1107 ensureCursorVisible();
1108 ensureLineVisible( 0 );
1116 const int endLine = lines() - 1;
1117 const int endLineLength = lineLength( endLine );
1118 setCursorPosition( endLine, endLineLength );
1119 ensureCursorVisible();
1120 ensureLineVisible( endLine );
1129 getCursorPosition( &line, &index );
1130 return positionFromLineIndex( line, index );
1136 lineIndexFromPosition( linearIndex, &line, &index );
1137 setCursorPosition( line, index );
1142 int startLine, startIndex, _;
1143 getSelection( &startLine, &startIndex, &_, &_ );
1144 if ( startLine == -1 )
1148 return positionFromLineIndex( startLine, startIndex );
1153 int endLine, endIndex, _;
1154 getSelection( &_, &_, &endLine, &endIndex );
1155 if ( endLine == -1 )
1159 return positionFromLineIndex( endLine, endIndex );
1164 int startLine, startIndex, endLine, endIndex;
1165 lineIndexFromPosition( start, &startLine, &startIndex );
1166 lineIndexFromPosition( end, &endLine, &endIndex );
1167 setSelection( startLine, startIndex, endLine, endIndex );
MessageLevel
Level for messages This will be used both for message log and message bar in application.
@ Warning
Warning message.
@ Critical
Critical/error message.
@ Info
Information message.
@ Success
Used for reporting a successful operation.
@ CheckSyntax
Language supports syntax checking.
@ Reformat
Language supports automatic code reformatting.
@ ToggleComment
Language supports comment toggling.
ScriptLanguage
Scripting languages.
@ QgisExpression
QGIS expressions.
@ Batch
Windows batch files.
@ Unknown
Unknown/other language.
QFlags< ScriptLanguageCapability > ScriptLanguageCapabilities
Script language capabilities.
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.
@ Decoration
Decoration color.
@ Identifier
Identifier 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.
@ Default
Default text color.
@ SearchMatchBackground
Background color for search matches (since QGIS 3.38)
@ CaretLine
Caret line color.
@ IndentationGuide
Indentation guide line.
@ Background
Background color.
@ SingleQuote
Single quote color.
@ MarginBackground
Margin background color.
@ SelectionBackground
Selection background color.
@ MatchedBraceForeground
Matched brace foreground color.
@ Operator
Operator 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...
@ 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.
static QgsCodeEditorColorSchemeRegistry * codeEditorColorSchemeRegistry()
Returns the global code editor color scheme registry, used for registering the color schemes for QgsC...
This class is a composition of two QSettings instances:
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
int findMinimalDistanceIndex(const QString &source, const QString &target)