diff --git a/data/Makefile.am b/data/Makefile.am index 082e92c56c..56f96ab306 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -63,6 +63,7 @@ filetypes_dist = \ filedefs/filetypes.php \ filedefs/filetypes.po \ filedefs/filetypes.powershell \ + filedefs/filetypes.prolog \ filedefs/filetypes.r \ filedefs/filetypes.restructuredtext \ filedefs/filetypes.ruby \ diff --git a/data/filedefs/filetypes.prolog b/data/filedefs/filetypes.prolog new file mode 100644 index 0000000000..cf757b5f02 --- /dev/null +++ b/data/filedefs/filetypes.prolog @@ -0,0 +1,78 @@ +[styling] +# Edit these in the colorscheme .conf file instead +default=default +key_major=keyword_1 +key_minor=keyword_2 +key_directive=keyword_1 +comment_block=comment +comment_line=comment +comment_key=comment +comment_key_error=comment +identifier=identifier +variable=default +anonymous=default +number=number_1 +operator=operator +string=string_1 +string_quote=string_1 +string_escape=string_1 +string_escape_error=error +string_eol=string_1 +embedded=string_1 +placeholder=string_1 + +[keywords] +# all items must be in one line +# From https://github.com/arthwang/vsc-prolog and https://github.com/mxw/vim-prolog +primary=abolish abolish_op abolish_record abort abs absolute_file_name accept access_file acos acyclic_term add_attribute alarm als append append_strings apply arg argc argv arithmetic_function arity array array_concat array_flat array_list asin assert asserta assertz at at_end_of_stream at_eof atan atom atom_chars atom_codes atom_concat atom_length atom_number atom_prefix atom_string atom_to_term atomic attach_suspensions attached_suspensions autoload autoload_tool b_external bag_abolish bag_count bag_create bag_dissolve bag_enter bag_erase bag_retrieve bagof begin_module between bind block breal breal_bounds breal_from_bounds breal_max breal_min byte_count bytes_to_term call call-2 call_c call_cleanup call_explicit call_priority call_with_depth_limit callable cancel_after_event canonical_path_name catch cd ceil ceiling char_code char_conversion char_int char_type character_count chdir clause clause_property close clrbit code_type collation_key comment compare compare_instances compile compile_predicates compile_stream compile_term compile_term_annotated compiled_stream compound concat_atom concat_atoms concat_string concat_strings connect copy_stream_data copy_term copy_term_vars coroutine cos coverof cputime create_module current_after_event current_after_events current_arithmetic_function current_array current_atom current_blob current_built_in current_char_conversion current_compiled_file current_domain current_error current_flag current_format_predicate current_functor current_interrupt current_key current_macro current_module current_module_predicate current_op current_ouput current_pragma current_predicate current_record current_signal current_store current_stream current_struct current_suspension current_trigger cyclic_term date date_time_stamp date_time_value dbgcomp debug debug_reset debugging decval define_error define_macro delay delayed_goals delayed_goals_number delete delete_file demon denominator deprecated dim discontiguous display div domain domain_index downcase_atom duplicate_term dwim_match dwim_predicate dynamic e elif ensure_loaded enter_suspension_list env erase erase_all erase_array erase_macro erase_module errno_id error_id eval event event_after event_after_every event_create event_disable event_enable event_retrieve events_after events_defer events_nodefer exec exec_group existing_file exists exists_directory exists_file exit exit_block exp expand_clause expand_file_name expand_goal expand_macros external fail fail_if false file_base_name file_directory_name file_name_extension fileerrors findall fix flag flatten_array float float_fractional_part float_integer_part floor flush flush_output forall fork format format_predicate format_time frandom functor garbage_collect garbage_collect_atoms gcd get get0 get_byte get_char get_chtab get_code get_error_handler get_event_handler get_file_info get_flag get_interrupt_handler get_leash get_module_info get_priority get_prompt get_single_char get_stream get_stream_info get_suspension_data get_time get_timer get_var_bounds get_var_info getbit getcwd getenv getval global global_op ground halt hash help ignore import incval index init_suspension_list inline insert_suspension instance integer integer_atom is is_absolute_file_name is_array is_built_in is_dynamic is_event is_handle is_list is_locked is_predicate is_record is_stream is_suspension join_string keysort kill kill_display_matrix kill_suspension lcm length lib line_count line_position listen listing ln load local local_record local_time local_time_string locale_sort lock lock_pass log lsb macro make make_array make_directory make_display_matrix make_local_array make_suspension maplist max memberchk merge merge_set merge_suspension_lists message_hook message_to_string meta meta_attribute meta_bind meta_predicate min mkdir mod mode module module_interface msb msort mutex mutex_init name nb_linkarg nb_setarg new_socket_server nl nodbgcomp nodebug nonground nonvar normalize_space nospy not not_unify notify_constrained notrace nth_clause number number_chars number_codes number_merge number_sort number_string numbervars numerator occurs on_signal once op open open_null_stream os_file_name parallel parse_time pathname pause peek_byte peek_char peek_code peer peer_deregister_multitask peer_do_multitask peer_get_property peer_multitask_confirm peer_multitask_terminate peer_queue_close peer_queue_create peer_queue_get_property peer_register_multitask phrase pi pipe plus popcount portray portray_clause portray_goal portray_term powm pragma pred predicate_property predsort print print_message print_message_lines printf profile prolog_to_os_filename prompt prompt1 prune_instances put put_byte put_char put_code qcompile random rational rationalize rdiv read read_annotated read_clause read_directory read_exdr read_history read_link read_pending_input read_string read_term read_token readvar real record record_create recorda recorded recorded_list recordz redefine_system_predicate reexport reference referenced_record rem remote_connect remote_connect_accept remote_connect_setup remote_disconnect remote_yield rename rename_file repeat rerecord reset_error_handler reset_error_handlers reset_event_handler retract retract_all retractall round same_file same_term schedule_suspensions schedule_woken see seed seeing seek seen select set_chtab set_error_handler set_event_handler set_flag set_input set_interrupt_handler set_leash set_output set_prolog_IO set_prompt set_stream set_stream_position set_stream_property set_suspension_data set_suspension_priority set_timer set_tty set_var_bounds setarg setbit setenv setlocale setof setup_and_call_cleanup setval sgn sh shelf shelf_abolish shelf_create shelf_dec shelf_get shelf_inc shelf_set shell sin size_file skip skipped sleep socket sort split_string sprintf spy spy_term spy_var sqrt stack_parameter stamp_date_time statistics store store_contains store_count store_create store_delete store_erase store_get store_inc store_set stored_keys stored_keys_and_values stream_position_data stream_property stream_select stream_truncate string string_code string_concat string_length string_list string_to_atom string_to_list struct sub_atom sub_string subcall subscript substring subsumes subsumes_chk succ suffix sum suspend suspension_to_goal suspensions swritef system tab tan tell telling term_hash term_string term_to_atom term_to_bytes term_variables test_and_setval throw time time_file times tmp_file told tool tool_body trace trace_call_port trace_exit_port trace_parent_port trace_point_port traceable trigger trim_stacks trimcore true truncate tty_get_capability tty_goto tty_put tty_size ttyflush tyi tyo type_of unget unifiable unify_with_occurs_check unix unlock unschedule_suspension unsetenv unskipped untraceable upcase_atom update_struct use_module var variable variant wait wait_for_input wake wildcard_match win_exec win_folder win_has_menu win_insert_menu win_insert_menu_item win_registry_get_value win_shell win_window_pos window_title with_output_to working_directory write write_canonical write_exdr write_term writeclause writef writeln writeq xget xor xset yield +# Visual Prolog keywords: https://wiki.visual-prolog.com/index.php?title=Language_Reference/Built-in_entities#Predicates +secondary=and anyflow apicall bininclude bound c class class_name clauses constant_name constants constructors convert delegate determ digits digitsOf do domains else elseif endif erroneous error errorExit export externally fact_address facts failure finally foreach free from fromEllipsis goal guard hasDomain if implement in include inherits interface isErroneous language lowerBound maxDigits message monitor multi namespace nondeterm options or orelse orrequires otherwise predicate_fullname predicate_name predicates procedure programPoint prolog properties requires resolve retractFactDb sizeBitsOf sizeOf sizeOfDomain sourcefile_lineno sourcefile_name sourcefile_timestamp stdcall succeed supports then thiscall toAny toBinary toBoolean toEllipsis toString toTerm trap try tryToTerm tryConvert typeDescriptorOf typeLibraryOf uncheckedConvert upperBound + +[lexer_properties] +lexer.visualprolog.verbatim.strings=0 +lexer.visualprolog.backquoted.strings=1 + +[settings] +# default extension used when saving files +extension=pro + +# MIME type +mime_type=text/x-prolog + +# these characters define word boundaries when making selections and searching +# using word matching options +#wordchars=_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 + +# single comments, like # in this file +comment_single=% +# multiline comments +#comment_open=/* +#comment_close=*/ + +# set to false if a comment character/string should start at column 0 of a line, true uses any +# indentation of the line, e.g. setting to true causes the following on pressing CTRL+d +# #command_example(); +# setting to false would generate this +# # command_example(); +# This setting works only for single line comments +comment_use_indent=true + +# context action command (please see Geany's main documentation for details) +context_action_cmd= + +[indentation] +#width=4 +# 0 is spaces, 1 is tabs, 2 is tab & spaces +#type=1 + +[build_settings] +# %f will be replaced by the complete filename +# %e will be replaced by the filename without extension +# (use only one of it at one time) +compiler=swipl -c "%f" + +run_cmd=swipl -q -s "%f" + +# Parse syntax check error messages and warnings, examples: +# ERROR: goo.pro:12: +error_regex=.+: (.+):([0-9]+).* diff --git a/data/filetype_extensions.conf b/data/filetype_extensions.conf index d8dc26e89c..6484ce497e 100644 --- a/data/filetype_extensions.conf +++ b/data/filetype_extensions.conf @@ -60,6 +60,7 @@ Pascal=*.pas;*.pp;*.inc;*.dpr;*.dpk; Perl=*.pl;*.perl;*.pm;*.agi;*.pod; PHP=*.php;*.php3;*.php4;*.php5;*.phtml; Po=*.po;*.pot; +Prolog=*.pro;*.P; Python=*.py;*.pyw;SConstruct;SConscript;wscript; PowerShell=*.ps1;*.psm1; reStructuredText=*.rest;*.reST;*.rst; diff --git a/meson.build b/meson.build index 5c7bc0a049..eec85fbaf3 100644 --- a/meson.build +++ b/meson.build @@ -297,6 +297,7 @@ lexilla = static_library('lexilla', 'scintilla/lexilla/lexers/LexTxt2tags.cxx', 'scintilla/lexilla/lexers/LexVerilog.cxx', 'scintilla/lexilla/lexers/LexVHDL.cxx', + 'scintilla/lexilla/lexers/LexVisualProlog.cxx', 'scintilla/lexilla/lexers/LexYAML.cxx', 'scintilla/lexilla/lexlib/Accessor.cxx', 'scintilla/lexilla/lexlib/Accessor.h', diff --git a/scintilla/Makefile.am b/scintilla/Makefile.am index bf430016bc..cbc9e9a93b 100644 --- a/scintilla/Makefile.am +++ b/scintilla/Makefile.am @@ -58,6 +58,7 @@ lexilla/lexers/LexTCL.cxx \ lexilla/lexers/LexTxt2tags.cxx \ lexilla/lexers/LexVHDL.cxx \ lexilla/lexers/LexVerilog.cxx \ +lexilla/lexers/LexVisualProlog.cxx \ lexilla/lexers/LexYAML.cxx LEXLIB_SRCS = \ diff --git a/scintilla/lexilla/lexers/LexVisualProlog.cxx b/scintilla/lexilla/lexers/LexVisualProlog.cxx new file mode 100644 index 0000000000..250ac5d74d --- /dev/null +++ b/scintilla/lexilla/lexers/LexVisualProlog.cxx @@ -0,0 +1,695 @@ +// Scintilla source code edit control +/** @file LexVisualProlog.cxx +** Lexer for Visual Prolog. +**/ +// Author Thomas Linder Puls, PDC A/S, http://www.visual-prolog.com +// Based on Lexer for C++, C, Java, and JavaScript. +// Copyright 1998-2005 by Neil Hodgson +// The License.txt file describes the conditions under which this software may be distributed. + +// The line state contains: +// In SCE_VISUALPROLOG_STRING: The closing quote and information about verbatim string. +// and a stack of nesting kinds: comment, embedded (syntax) and (syntax) place holder + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(disable: 4786) +#endif + +#include +#include +#include +#include +#include +#include + +#include "ILexer.h" +#include "Scintilla.h" +#include "SciLexer.h" + +#include "WordList.h" +#include "LexAccessor.h" +#include "Accessor.h" +#include "StyleContext.h" +#include "CharacterSet.h" +#include "CharacterCategory.h" +#include "LexerModule.h" +#include "OptionSet.h" +#include "DefaultLexer.h" + +using namespace Scintilla; +using namespace Lexilla; + +namespace { +// Options used for LexerVisualProlog +struct OptionsVisualProlog { + bool verbatimStrings; + bool backQuotedStrings; + OptionsVisualProlog() { + verbatimStrings = true; + backQuotedStrings = false; + } +}; + +static const char* const visualPrologWordLists[] = { + "Major keywords (class, predicates, ...)", + "Minor keywords (if, then, try, ...)", + "Directive keywords without the '#' (include, requires, ...)", + "Documentation keywords without the '@' (short, detail, ...)", + 0, +}; + +struct OptionSetVisualProlog : public OptionSet { + OptionSetVisualProlog() { + DefineProperty("lexer.visualprolog.verbatim.strings", &OptionsVisualProlog::verbatimStrings, + "Set to 0 to disable highlighting verbatim strings using '@'."); + DefineProperty("lexer.visualprolog.backquoted.strings", &OptionsVisualProlog::backQuotedStrings, + "Set to 1 to enable using back quotes (``) to delimit strings."); + DefineWordListSets(visualPrologWordLists); + } +}; + +LexicalClass lexicalClasses[] = { + SCE_VISUALPROLOG_DEFAULT, "SCE_VISUALPROLOG_DEFAULT", "default", "Default style", + SCE_VISUALPROLOG_KEY_MAJOR, "SCE_VISUALPROLOG_KEY_MAJOR", "keyword major", "Major keyword", + SCE_VISUALPROLOG_KEY_MINOR, "SCE_VISUALPROLOG_KEY_MINOR", "keyword minor", "Minor keyword", + SCE_VISUALPROLOG_KEY_DIRECTIVE, "SCE_VISUALPROLOG_KEY_DIRECTIVE", "keyword preprocessor", "Directove keyword", + SCE_VISUALPROLOG_COMMENT_BLOCK, "SCE_VISUALPROLOG_COMMENT_BLOCK", "comment", "Multiline comment /* */", + SCE_VISUALPROLOG_COMMENT_LINE, "SCE_VISUALPROLOG_COMMENT_LINE", "comment line", "Line comment % ...", + SCE_VISUALPROLOG_COMMENT_KEY, "SCE_VISUALPROLOG_COMMENT_KEY", "comment documentation keyword", "Doc keyword in comment % @short ...", + SCE_VISUALPROLOG_COMMENT_KEY_ERROR, "SCE_VISUALPROLOG_COMMENT_KEY_ERROR", "comment", "A non recognized doc keyword % @qqq ...", + SCE_VISUALPROLOG_IDENTIFIER, "SCE_VISUALPROLOG_IDENTIFIER", "identifier", "Identifier (black)", + SCE_VISUALPROLOG_VARIABLE, "SCE_VISUALPROLOG_VARIABLE", "variable identifier", "Variable (green)", + SCE_VISUALPROLOG_ANONYMOUS, "SCE_VISUALPROLOG_ANONYMOUS", "variable anonymous identifier", "Anonymous Variable _XXX (dimmed green)", + SCE_VISUALPROLOG_NUMBER, "SCE_VISUALPROLOG_NUMBER", "numeric", "Number", + SCE_VISUALPROLOG_OPERATOR, "SCE_VISUALPROLOG_OPERATOR", "operator", "Operator", + SCE_VISUALPROLOG_STRING, "SCE_VISUALPROLOG_STRING", "literal string", "String literal", + SCE_VISUALPROLOG_STRING_QUOTE, "SCE_VISUALPROLOG_STRING_QUOTE", "literal string quote", "Quotes surrounding string literals", + SCE_VISUALPROLOG_STRING_ESCAPE, "SCE_VISUALPROLOG_STRING_ESCAPE", "literal string escapesequence", "Escape sequence in string literal", + SCE_VISUALPROLOG_STRING_ESCAPE_ERROR, "SCE_VISUALPROLOG_STRING_ESCAPE_ERROR", "error literal string escapesequence", "Error in escape sequence in string literal", + SCE_VISUALPROLOG_STRING_EOL, "SCE_VISUALPROLOG_STRING_EOL", "literal string multiline raw escapesequence", "Verbatim/multiline string literal EOL", + SCE_VISUALPROLOG_EMBEDDED, "SCE_VISUALPROLOG_EMBEDDED", "literal string embedded", "Embedded syntax [| ... |]", + SCE_VISUALPROLOG_PLACEHOLDER, "SCE_VISUALPROLOG_PLACEHOLDER", "operator embedded", "Syntax place holder {| ... |}:ident in embedded syntax" +}; + +LexicalClass getLexicalClass(int style) { + for (auto lc : lexicalClasses) { + if (style == lc.value) { + return lc; + } + } + return {style, "", "unused", ""}; +} + + +class LexerVisualProlog : public DefaultLexer { + WordList majorKeywords; + WordList minorKeywords; + WordList directiveKeywords; + WordList docKeywords; + OptionsVisualProlog options; + OptionSetVisualProlog osVisualProlog; +public: + LexerVisualProlog() : DefaultLexer("visualprolog", SCLEX_VISUALPROLOG) { + } + virtual ~LexerVisualProlog() { + } + void SCI_METHOD Release() override { + delete this; + } + int SCI_METHOD Version() const override { + return lvRelease5; + } + const char* SCI_METHOD PropertyNames() override { + return osVisualProlog.PropertyNames(); + } + int SCI_METHOD PropertyType(const char* name) override { + return osVisualProlog.PropertyType(name); + } + const char* SCI_METHOD DescribeProperty(const char* name) override { + return osVisualProlog.DescribeProperty(name); + } + Sci_Position SCI_METHOD PropertySet(const char* key, const char* val) override; + const char* SCI_METHOD PropertyGet(const char* key) override { + return osVisualProlog.PropertyGet(key); + } + const char* SCI_METHOD DescribeWordListSets() override { + return osVisualProlog.DescribeWordListSets(); + } + Sci_Position SCI_METHOD WordListSet(int n, const char* wl) override; + void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument* pAccess) override; + void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument* pAccess) override; + + void* SCI_METHOD PrivateCall(int, void*) override { + return 0; + } + + int SCI_METHOD NamedStyles() override { + int namedStyles = 0; + for (auto lc : lexicalClasses) { + if (namedStyles < lc.value) { + namedStyles = lc.value; + } + } + return namedStyles; + } + const char* SCI_METHOD NameOfStyle(int style) override { + return getLexicalClass(style).name; + } + const char* SCI_METHOD TagsOfStyle(int style) override { + return getLexicalClass(style).tags; + } + const char* SCI_METHOD DescriptionOfStyle(int style) override { + return getLexicalClass(style).description; + } + + static ILexer5* LexerFactoryVisualProlog() { + return new LexerVisualProlog(); + } +}; + +Sci_Position SCI_METHOD LexerVisualProlog::PropertySet(const char* key, const char* val) { + if (osVisualProlog.PropertySet(&options, key, val)) { + return 0; + } + return -1; +} + +Sci_Position SCI_METHOD LexerVisualProlog::WordListSet(int n, const char* wl) { + WordList* wordListN = 0; + switch (n) { + case 0: + wordListN = &majorKeywords; + break; + case 1: + wordListN = &minorKeywords; + break; + case 2: + wordListN = &directiveKeywords; + break; + case 3: + wordListN = &docKeywords; + break; + } + Sci_Position firstModification = -1; + if (wordListN) { + WordList wlNew; + wlNew.Set(wl); + if (*wordListN != wlNew) { + wordListN->Set(wl); + firstModification = 0; + } + } + return firstModification; +} + +static bool isLowerLetter(int ch) { + return ccLl == CategoriseCharacter(ch); +} + +static bool isUpperLetter(int ch) { + return ccLu == CategoriseCharacter(ch); +} + +static bool isAlphaNum(int ch) { + CharacterCategory cc = CategoriseCharacter(ch); + return (ccLu == cc || ccLl == cc || ccLt == cc || ccLm == cc || ccLo == cc || ccNd == cc || ccNl == cc || ccNo == cc); +} + +static bool isStringVerbatimOpenClose(int ch) { + CharacterCategory cc = CategoriseCharacter(ch); + return (ccPc <= cc && cc <= ccSo); +} + +static bool isIdChar(int ch) { + return ('_') == ch || isAlphaNum(ch); +} + +// Look ahead to see which colour "end" should have (takes colour after the following keyword) +static void endLookAhead(char s[], LexAccessor& styler, Sci_Position start) { + char ch = styler.SafeGetCharAt(start, '\n'); + while (' ' == ch) { + start++; + ch = styler.SafeGetCharAt(start, '\n'); + } + Sci_Position i = 0; + while (i < 100 && isLowerLetter(ch)) { + s[i] = ch; + i++; + ch = styler.SafeGetCharAt(start + i, '\n'); + } + s[i] = '\0'; +} + + +class lineState { +public: + bool verbatim = false; + int closingQuote = 0; + int kindStack = 0; + + bool isOpenStringVerbatim(int next) { + if (next > 0x7FFF) { + return false; + } + switch (next) { + case L'<': + closingQuote = L'>'; + return true; + case L'>': + closingQuote = L'<'; + return true; + case L'(': + closingQuote = L')'; + return true; + case L')': + closingQuote = L'('; + return true; + case L'[': + closingQuote = L']'; + return true; + case L']': + closingQuote = L'['; + return true; + case L'{': + closingQuote = L'}'; + return true; + case L'}': + closingQuote = L'{'; + return true; + case L'_': + case L'.': + case L',': + case L';': + return false; + default: + if (isStringVerbatimOpenClose(next)) { + closingQuote = next; + return true; + } else { + return false; + } + } + } + + enum kind { + none = 0, + comment = 1, + embedded = 2, + placeholder = 3 + }; + + void setState(int state) { + verbatim = state >> 31; + closingQuote = state >> 16 & 0x7FFF; + kindStack = state & 0xFFFF; + } + + int getState() { + return verbatim << 31 | closingQuote << 16 | (kindStack & 0xFFFF); + } + + void enter(kind k) { + kindStack = kindStack << 2 | k; + } + + void leave(kind k) { + if (k == currentKind()) { + kindStack = kindStack >> 2; + } + } + kind currentKind() { + return static_cast(kindStack & 0x3); + } + kind stateKind2(int ks) { + if (0 == ks) { + return none; + } else { + kind k1 = stateKind2(ks >> 2); + kind k2 = static_cast(ks & 0x3); + if (embedded == k1 && k2 == comment) { + return embedded; + } else { + return k2; + } + } + } + kind stateKind() { + return stateKind2(kindStack); + } +}; + +void SCI_METHOD LexerVisualProlog::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument* pAccess) { + LexAccessor styler(pAccess); + CharacterSet setDoxygen(CharacterSet::setAlpha, ""); + CharacterSet setNumber(CharacterSet::setNone, "0123456789abcdefABCDEFxoXO_"); + + StyleContext sc(startPos, length, initStyle, styler, 0x7f); + + int styleBeforeDocKeyword = SCE_VISUALPROLOG_DEFAULT; + + lineState ls; + if (sc.currentLine >= 1) { + ls.setState(styler.GetLineState(sc.currentLine - 1)); + } + + bool newState = false; + + for (; sc.More(); sc.Forward()) { + + Sci_Position currentLineEntry = sc.currentLine; + + if (newState) { + newState = false; + int state; + switch (ls.stateKind()) { + case lineState::comment: + state = SCE_VISUALPROLOG_COMMENT_BLOCK; + break; + case lineState::embedded: + state = SCE_VISUALPROLOG_EMBEDDED; + break; + case lineState::placeholder: + state = SCE_VISUALPROLOG_PLACEHOLDER; + break; + default: + state = SCE_VISUALPROLOG_DEFAULT; + break; + } + sc.SetState(state); + } + + // Determine if the current state should terminate. + switch (sc.state) { + case SCE_VISUALPROLOG_OPERATOR: + sc.SetState(SCE_VISUALPROLOG_DEFAULT); + break; + case SCE_VISUALPROLOG_NUMBER: + // We accept almost anything because of hex, '.' and number suffixes + if (!(setNumber.Contains(sc.ch)) || (sc.Match('.') && IsADigit(sc.chNext))) { + sc.SetState(SCE_VISUALPROLOG_DEFAULT); + } + break; + case SCE_VISUALPROLOG_IDENTIFIER: + if (!isIdChar(sc.ch)) { + char s[1000]; + sc.GetCurrent(s, sizeof(s)); + if (0 == strcmp(s, "end")) { + endLookAhead(s, styler, sc.currentPos); + } + if (majorKeywords.InList(s)) { + sc.ChangeState(SCE_VISUALPROLOG_KEY_MAJOR); + } else if (minorKeywords.InList(s)) { + sc.ChangeState(SCE_VISUALPROLOG_KEY_MINOR); + } + sc.SetState(SCE_VISUALPROLOG_DEFAULT); + } + break; + case SCE_VISUALPROLOG_VARIABLE: + case SCE_VISUALPROLOG_ANONYMOUS: + if (!isIdChar(sc.ch)) { + sc.SetState(SCE_VISUALPROLOG_DEFAULT); + } + break; + case SCE_VISUALPROLOG_KEY_DIRECTIVE: + if (!isLowerLetter(sc.ch)) { + char s[1000]; + sc.GetCurrent(s, sizeof(s)); + if (!directiveKeywords.InList(s + 1)) { + sc.ChangeState(SCE_VISUALPROLOG_IDENTIFIER); + } + sc.SetState(SCE_VISUALPROLOG_DEFAULT); + } + break; + case SCE_VISUALPROLOG_COMMENT_LINE: + if (sc.MatchLineEnd()) { + int nextState = (lineState::comment == ls.currentKind()) ? SCE_VISUALPROLOG_COMMENT_BLOCK : SCE_VISUALPROLOG_DEFAULT; + sc.SetState(nextState); + } else if (sc.Match('@')) { + styleBeforeDocKeyword = SCE_VISUALPROLOG_COMMENT_LINE; + sc.SetState(SCE_VISUALPROLOG_COMMENT_KEY_ERROR); + } + break; + case SCE_VISUALPROLOG_COMMENT_BLOCK: + if (sc.Match('*', '/')) { + sc.Forward(); + ls.leave(lineState::comment); + newState = true; + } else if (sc.Match('/', '*')) { + sc.Forward(); + ls.enter(lineState::comment); + } else if (sc.Match('@')) { + styleBeforeDocKeyword = SCE_VISUALPROLOG_COMMENT_BLOCK; + sc.SetState(SCE_VISUALPROLOG_COMMENT_KEY_ERROR); + } + break; + case SCE_VISUALPROLOG_COMMENT_KEY_ERROR: + if (!setDoxygen.Contains(sc.ch) || sc.MatchLineEnd()) { + char s[1000]; + sc.GetCurrent(s, sizeof(s)); + if (docKeywords.InList(s + 1)) { + sc.ChangeState(SCE_VISUALPROLOG_COMMENT_KEY); + } + if (SCE_VISUALPROLOG_COMMENT_LINE == styleBeforeDocKeyword && sc.MatchLineEnd()) { + // end line comment + int nextState = (lineState::comment == ls.currentKind()) ? SCE_VISUALPROLOG_COMMENT_BLOCK : SCE_VISUALPROLOG_DEFAULT; + sc.SetState(nextState); + } else { + sc.SetState(styleBeforeDocKeyword); + if (SCE_VISUALPROLOG_COMMENT_BLOCK == styleBeforeDocKeyword && sc.Match('*', '/')) { + // we have consumed the '*' if it comes immediately after the docKeyword + sc.Forward(); + ls.leave(lineState::comment); + newState = true; + } + } + } + break; + case SCE_VISUALPROLOG_STRING_ESCAPE_ERROR: + if (sc.atLineStart) { + sc.SetState(SCE_VISUALPROLOG_DEFAULT); + break; + } + [[fallthrough]]; + case SCE_VISUALPROLOG_STRING_ESCAPE: + case SCE_VISUALPROLOG_STRING_QUOTE: + case SCE_VISUALPROLOG_STRING_EOL: + // return to SCE_VISUALPROLOG_STRING and treat as such (fallthrough) + sc.SetState(SCE_VISUALPROLOG_STRING); + [[fallthrough]]; + case SCE_VISUALPROLOG_STRING: + if (sc.MatchLineEnd() | sc.atLineEnd) { + if (ls.verbatim) { + sc.SetState(SCE_VISUALPROLOG_STRING_EOL); + } else { + ls.closingQuote = 0; + sc.SetState(SCE_VISUALPROLOG_STRING_ESCAPE_ERROR); + } + } else if (sc.Match(ls.closingQuote)) { + if (ls.verbatim && ls.closingQuote == sc.chNext) { + sc.SetState(SCE_VISUALPROLOG_STRING_ESCAPE); + sc.Forward(); + } else { + ls.closingQuote = 0; + sc.SetState(SCE_VISUALPROLOG_STRING_QUOTE); + sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT); + } + } else if (!ls.verbatim && sc.Match('\\')) { + sc.SetState(SCE_VISUALPROLOG_STRING_ESCAPE_ERROR); + sc.Forward(); + if (sc.MatchLineEnd()) { + sc.ForwardSetState(SCE_VISUALPROLOG_DEFAULT); + } else { + if (sc.Match('"') || sc.Match('\'') || sc.Match('\\') || sc.Match('n') || sc.Match('l') || sc.Match('r') || sc.Match('t')) { + sc.ChangeState(SCE_VISUALPROLOG_STRING_ESCAPE); + } else if (sc.Match('u')) { + if (IsADigit(sc.chNext, 16)) { + sc.Forward(); + if (IsADigit(sc.chNext, 16)) { + sc.Forward(); + if (IsADigit(sc.chNext, 16)) { + sc.Forward(); + if (IsADigit(sc.chNext, 16)) { + sc.Forward(); + sc.ChangeState(SCE_VISUALPROLOG_STRING_ESCAPE); + } + } + } + } + } + } + } + break; + case SCE_VISUALPROLOG_EMBEDDED: + if (sc.Match('|', ']')) { + sc.Forward(); + ls.leave(lineState::embedded); + newState = true; + } else if (sc.Match('[', '|')) { + sc.Forward(); + ls.enter(lineState::embedded); + } else if (sc.Match('{', '|') && lineState::comment != ls.currentKind()) { + sc.SetState(SCE_VISUALPROLOG_DEFAULT); + } else if (sc.Match('/', '*')) { + sc.Forward(); + ls.enter(lineState::comment); + } else if (sc.Match('*', '/')) { + sc.Forward(); + ls.leave(lineState::comment); + newState = true; + } + break; + case SCE_VISUALPROLOG_PLACEHOLDER: + if (lineState::embedded == ls.currentKind()) { + sc.SetState(SCE_VISUALPROLOG_EMBEDDED); + } else { + sc.SetState(SCE_VISUALPROLOG_DEFAULT); + } + break; + } + + if (currentLineEntry != sc.currentLine) { + styler.SetLineState(currentLineEntry, ls.getState()); + } + if (sc.MatchLineEnd() | sc.atLineEnd) { + if (sc.More()) { // currentLine can be outside the document + styler.SetLineState(sc.currentLine, ls.getState()); + } + } + + // Determine if a new state should be entered. + if (sc.state == SCE_VISUALPROLOG_DEFAULT) { + if (options.verbatimStrings && sc.Match('@') && ls.isOpenStringVerbatim(sc.chNext)) { + ls.verbatim = true; + sc.SetState(SCE_VISUALPROLOG_STRING_QUOTE); + sc.Forward(); + } else if (IsADigit(sc.ch) || (sc.Match('.') && IsADigit(sc.chNext))) { + sc.SetState(SCE_VISUALPROLOG_NUMBER); + } else if (isLowerLetter(sc.ch)) { + sc.SetState(SCE_VISUALPROLOG_IDENTIFIER); + } else if (isUpperLetter(sc.ch)) { + sc.SetState(SCE_VISUALPROLOG_VARIABLE); + } else if (sc.Match('_')) { + sc.SetState(SCE_VISUALPROLOG_ANONYMOUS); + } else if (sc.Match('/', '*')) { + sc.SetState(SCE_VISUALPROLOG_COMMENT_BLOCK); + ls.enter(lineState::comment); + sc.Forward(); + } else if (sc.Match('%')) { + sc.SetState(SCE_VISUALPROLOG_COMMENT_LINE); + } else if (sc.Match('[', '|')) { + sc.SetState(SCE_VISUALPROLOG_EMBEDDED); + ls.enter(lineState::embedded); + sc.Forward(); + } else if (sc.Match('{', '|')) { + sc.SetState(SCE_VISUALPROLOG_PLACEHOLDER); + ls.enter(lineState::placeholder); + sc.Forward(); + } else if (sc.Match('|', '}')) { + sc.SetState(SCE_VISUALPROLOG_PLACEHOLDER); + sc.Forward(); + if (':' == sc.chNext) { + sc.Forward(); + for (; isIdChar(sc.chNext); sc.Forward()) { + } + } + ls.leave(lineState::placeholder); + newState = true; + } else if (sc.Match('\'')) { + ls.verbatim = false; + ls.closingQuote = '\''; + sc.SetState(SCE_VISUALPROLOG_STRING_QUOTE); + } else if (sc.Match('"')) { + ls.verbatim = false; + ls.closingQuote = '"'; + sc.SetState(SCE_VISUALPROLOG_STRING_QUOTE); + } else if (options.backQuotedStrings && sc.Match('`')) { + ls.verbatim = false; + ls.closingQuote = '`'; + sc.SetState(SCE_VISUALPROLOG_STRING_QUOTE); + } else if (sc.Match('#')) { + sc.SetState(SCE_VISUALPROLOG_KEY_DIRECTIVE); + } else if (isoperator(static_cast(sc.ch)) || sc.Match('\\') || + (!options.verbatimStrings && sc.Match('@'))) { + sc.SetState(SCE_VISUALPROLOG_OPERATOR); + } + } + } + sc.Complete(); + styler.Flush(); +} + +// Store both the current line's fold level and the next lines in the +// level store to make it easy to pick up with each increment +// and to make it possible to fiddle the current level for "} else {". + +#if defined(__clang__) +#if __has_warning("-Wunused-but-set-variable") +// Disable warning for visibleChars +#pragma clang diagnostic ignored "-Wunused-but-set-variable" +#endif +#endif + +void SCI_METHOD LexerVisualProlog::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument* pAccess) { + + LexAccessor styler(pAccess); + + Sci_PositionU endPos = startPos + length; + int visibleChars = 0; + Sci_Position currentLine = styler.GetLine(startPos); + int levelCurrent = SC_FOLDLEVELBASE; + if (currentLine > 0) + levelCurrent = styler.LevelAt(currentLine - 1) >> 16; + int levelMinCurrent = levelCurrent; + int levelNext = levelCurrent; + char chNext = styler[startPos]; + int styleNext = styler.StyleAt(startPos); + int style = initStyle; + for (Sci_PositionU i = startPos; i < endPos; i++) { + char ch = chNext; + chNext = styler.SafeGetCharAt(i + 1); + style = styleNext; + styleNext = styler.StyleAt(i + 1); + bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n'); + if (style == SCE_VISUALPROLOG_OPERATOR) { + if (ch == '{') { + // Measure the minimum before a '{' to allow + // folding on "} else {" + if (levelMinCurrent > levelNext) { + levelMinCurrent = levelNext; + } + levelNext++; + } else if (ch == '}') { + levelNext--; + } + } + if (!IsASpace(ch)) + visibleChars++; + if (atEOL || (i == endPos - 1)) { + int levelUse = levelCurrent; + int lev = levelUse | levelNext << 16; + if (levelUse < levelNext) + lev |= SC_FOLDLEVELHEADERFLAG; + if (lev != styler.LevelAt(currentLine)) { + styler.SetLevel(currentLine, lev); + } + currentLine++; + levelCurrent = levelNext; + levelMinCurrent = levelCurrent; + if (atEOL && (i == static_cast(styler.Length() - 1))) { + // There is an empty line at end of file so give it same level and empty + styler.SetLevel(currentLine, (levelCurrent | levelCurrent << 16) | SC_FOLDLEVELWHITEFLAG); + } + visibleChars = 0; + } + } +} +} + +LexerModule lmVisualProlog(SCLEX_VISUALPROLOG, LexerVisualProlog::LexerFactoryVisualProlog, "visualprolog", visualPrologWordLists); diff --git a/scintilla/lexilla/src/Lexilla.cxx b/scintilla/lexilla/src/Lexilla.cxx index d66b3ff482..96d9f9ee28 100644 --- a/scintilla/lexilla/src/Lexilla.cxx +++ b/scintilla/lexilla/src/Lexilla.cxx @@ -218,6 +218,7 @@ static void AddGeanyLexers() &lmTxt2tags, &lmVerilog, &lmVHDL, + &lmVisualProlog, &lmXML, &lmYAML, }); diff --git a/scintilla/scintilla_changes.patch b/scintilla/scintilla_changes.patch index e76ed257bb..e9fe608995 100644 --- a/scintilla/scintilla_changes.patch +++ b/scintilla/scintilla_changes.patch @@ -117,6 +117,7 @@ index cd4b23617..af4a73db4 100644 + &lmTxt2tags, + &lmVerilog, + &lmVHDL, ++ &lmVisualProlog, + &lmXML, + &lmYAML, + }); diff --git a/src/filetypes.c b/src/filetypes.c index 6e2917a96e..bbd0902e95 100644 --- a/src/filetypes.c +++ b/src/filetypes.c @@ -189,6 +189,7 @@ static void init_builtin_filetypes(void) FT_INIT( SMALLTALK, NONE, "Smalltalk", NULL, SOURCE_FILE, SCRIPT ); FT_INIT( JULIA, JULIA, "Julia", NULL, SOURCE_FILE, SCRIPT ); FT_INIT( AU3, AUTOIT, "AutoIt", NULL, SCRIPT, SCRIPT ); + FT_INIT( PROLOG, NONE, "Prolog", NULL, SOURCE_FILE, COMPILED ); } diff --git a/src/filetypes.h b/src/filetypes.h index 77d6c78b76..1b1f8ddf1f 100644 --- a/src/filetypes.h +++ b/src/filetypes.h @@ -109,6 +109,7 @@ typedef enum GEANY_FILETYPES_SMALLTALK, GEANY_FILETYPES_JULIA, GEANY_FILETYPES_AU3, + GEANY_FILETYPES_PROLOG, /* ^ append items here */ GEANY_MAX_BUILT_IN_FILETYPES /* Don't use this, use filetypes_array->len instead */ } diff --git a/src/highlighting.c b/src/highlighting.c index 9cc5bf2b2c..d3efebabf3 100644 --- a/src/highlighting.c +++ b/src/highlighting.c @@ -1041,6 +1041,7 @@ void highlighting_init_styles(guint filetype_idx, GKeyFile *config, GKeyFile *co init_styleset_case(PHP); init_styleset_case(PO); init_styleset_case(POWERSHELL); + init_styleset_case(PROLOG); init_styleset_case(PYTHON); init_styleset_case(R); init_styleset_case(RUBY); @@ -1133,6 +1134,7 @@ void highlighting_set_styles(ScintillaObject *sci, GeanyFiletype *ft) styleset_case(PHP); styleset_case(PO); styleset_case(POWERSHELL); + styleset_case(PROLOG); styleset_case(PYTHON); styleset_case(R); styleset_case(RUBY); @@ -1634,6 +1636,15 @@ gboolean highlighting_is_string_style(gint lexer, gint style) return (style == SCE_POWERSHELL_STRING || style == SCE_POWERSHELL_CHARACTER); + case SCLEX_VISUALPROLOG: + return (style == SCE_VISUALPROLOG_STRING || + style == SCE_VISUALPROLOG_STRING_QUOTE || + style == SCE_VISUALPROLOG_STRING_ESCAPE || + style == SCE_VISUALPROLOG_STRING_ESCAPE_ERROR || + style == SCE_VISUALPROLOG_STRING_EOL || + style == SCE_VISUALPROLOG_EMBEDDED || + style == SCE_VISUALPROLOG_PLACEHOLDER); + case SCLEX_BATCH: case SCLEX_DIFF: case SCLEX_LATEX: @@ -1877,6 +1888,12 @@ gboolean highlighting_is_comment_style(gint lexer, gint style) case SCLEX_AU3: return (style == SCE_AU3_COMMENT || style == SCE_AU3_COMMENTBLOCK); + + case SCLEX_VISUALPROLOG: + return (style == SCE_VISUALPROLOG_COMMENT_BLOCK || + style == SCE_VISUALPROLOG_COMMENT_LINE || + style == SCE_VISUALPROLOG_COMMENT_KEY || + style == SCE_VISUALPROLOG_COMMENT_KEY_ERROR); } return FALSE; } diff --git a/src/highlightingmappings.h b/src/highlightingmappings.h index f54498e2ac..d15b2971f5 100644 --- a/src/highlightingmappings.h +++ b/src/highlightingmappings.h @@ -1327,6 +1327,39 @@ static const HLKeyword highlighting_keywords_POWERSHELL[] = #define highlighting_properties_POWERSHELL EMPTY_PROPERTIES +/* Prolog */ +#define highlighting_lexer_PROLOG SCLEX_VISUALPROLOG +static const HLStyle highlighting_styles_PROLOG[] = +{ + { SCE_VISUALPROLOG_DEFAULT, "default", FALSE }, + { SCE_VISUALPROLOG_KEY_MAJOR, "key_major", FALSE }, + { SCE_VISUALPROLOG_KEY_MINOR, "key_minor", FALSE }, + { SCE_VISUALPROLOG_KEY_DIRECTIVE, "key_directive", FALSE }, + { SCE_VISUALPROLOG_COMMENT_BLOCK, "comment_block", FALSE }, + { SCE_VISUALPROLOG_COMMENT_LINE, "comment_line", FALSE }, + { SCE_VISUALPROLOG_COMMENT_KEY, "comment_key", FALSE }, + { SCE_VISUALPROLOG_COMMENT_KEY_ERROR, "comment_key_error", FALSE }, + { SCE_VISUALPROLOG_IDENTIFIER, "identifier", FALSE }, + { SCE_VISUALPROLOG_VARIABLE, "variable", FALSE }, + { SCE_VISUALPROLOG_ANONYMOUS, "anonymous", FALSE }, + { SCE_VISUALPROLOG_NUMBER, "number", FALSE }, + { SCE_VISUALPROLOG_OPERATOR, "operator", FALSE }, + { SCE_VISUALPROLOG_STRING, "string", FALSE }, + { SCE_VISUALPROLOG_STRING_QUOTE, "string_quote", FALSE }, + { SCE_VISUALPROLOG_STRING_ESCAPE, "string_escape", FALSE }, + { SCE_VISUALPROLOG_STRING_ESCAPE_ERROR, "string_escape_error", FALSE }, + { SCE_VISUALPROLOG_STRING_EOL, "string_eol", FALSE }, + { SCE_VISUALPROLOG_EMBEDDED, "embedded", FALSE }, + { SCE_VISUALPROLOG_PLACEHOLDER, "placeholder", FALSE }, +}; +static const HLKeyword highlighting_keywords_PROLOG[] = +{ + { 0, "primary", FALSE }, + { 1, "secondary", FALSE }, +}; +#define highlighting_properties_PROLOG EMPTY_PROPERTIES + + /* Python */ #define highlighting_lexer_PYTHON SCLEX_PYTHON static const HLStyle highlighting_styles_PYTHON[] =