diff --git a/ChangeLog b/ChangeLog index ab3fd7ef..1c86893a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,12 @@ * geany.glade, src/interface.c, src/notebook.c: Revert previous notebook focus changes as this disables the tab scroll arrows. + * scintilla/include/SciLexer.h, scintilla/include/Scintilla.iface, + scintilla/KeyWords.cxx, scintilla/LexOthers.cxx, src/templates.c, + src/highlighting.c, src/plugindata.h, src/filetypes.c, + src/filetypes.h, src/editor.c, data/filetype_extensions.conf, + data/filetypes.po: + Add new filetype 'Gettext translation file' (closes #2131985). 2008-09-27 Enrico Tröger diff --git a/data/filetype_extensions.conf b/data/filetype_extensions.conf index d203cabe..b8f3b23b 100644 --- a/data/filetype_extensions.conf +++ b/data/filetype_extensions.conf @@ -13,7 +13,7 @@ D=*.d;*.di; F77=*.f;*.for;*.ftn;*.f77; Fortran=*.f90;*.f95;*.f03; FreeBasic=*.bas;*.bi; -GLSL=*.glsl;*.frag;*.vert +GLSL=*.glsl;*.frag;*.vert; Haskell=*.hs;*.lhs; Haxe=*.hx; Java=*.java;*.jsp; @@ -40,4 +40,5 @@ Diff=*.diff;*.patch;*.rej; LaTeX=*.tex;*.sty;*.idx;*.ltx; reStructuredText=*.rest;*.reST;*.rst; SQL=*.sql; +Po=*.po;*.pot; None=*; diff --git a/data/filetypes.po b/data/filetypes.po new file mode 100644 index 00000000..4ffbaf61 --- /dev/null +++ b/data/filetypes.po @@ -0,0 +1,45 @@ +# For complete documentation of this file, please see Geany's main documentation +[styling] +# foreground;background;bold;italic +default=0x7f0000;0xffffff;false;false +comment=0x808080;0xffffff;false;false +msgid=0x00007f;0xffffff;true;false +msgid_text=0x00007f;0xffffff;false;false +msgstr=0x7f0000;0xffffff;true;false +msgstr_text=0x7f0000;0xffffff;false;false +msgctxt=0x007f00;0xffffff;true;false +msgctxt_text=0x007f00;0xffffff;false;false +fuzzy=0xffa500;0xffffff;true;false + +# the lexer don't support keywords + + +[settings] +# default extension used when saving files +#extension=po + +# the following characters are these which a "word" can contains, see documentation +#wordchars=_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 + +# if only single comment char is supported like # in this file, leave comment_close blank +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= + + +[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=msgfmt --check --check-accelerators=_ "%f" + diff --git a/scintilla/KeyWords.cxx b/scintilla/KeyWords.cxx index ca7db47f..586001d9 100644 --- a/scintilla/KeyWords.cxx +++ b/scintilla/KeyWords.cxx @@ -167,6 +167,7 @@ int Scintilla_LinkLexers() { LINK_LEXER(lmPerl); LINK_LEXER(lmPHP); LINK_LEXER(lmPHPSCRIPT); + LINK_LEXER(lmPo); LINK_LEXER(lmProps); LINK_LEXER(lmPython); LINK_LEXER(lmR); diff --git a/scintilla/LexOthers.cxx b/scintilla/LexOthers.cxx index ad015c9b..430e5415 100644 --- a/scintilla/LexOthers.cxx +++ b/scintilla/LexOthers.cxx @@ -24,6 +24,10 @@ using namespace Scintilla; #endif +static bool strstart(const char *haystack, const char *needle) { + return strncmp(haystack, needle, strlen(needle)) == 0; +} + static bool Is0To9(char ch) { return (ch >= '0') && (ch <= '9'); } @@ -582,6 +586,77 @@ static void FoldDiffDoc(unsigned int startPos, int length, int, WordList*[], Acc } while (static_cast(startPos) + length > curLineStart); } +static void ColourisePoLine( + char *lineBuffer, + unsigned int lengthLine, + unsigned int startLine, + unsigned int endPos, + Accessor &styler) { + + unsigned int i = 0; + static unsigned int state = SCE_PO_DEFAULT; + unsigned int state_start = SCE_PO_DEFAULT; + + while ((i < lengthLine) && isspacechar(lineBuffer[i])) // Skip initial spaces + i++; + if (i < lengthLine) { + if (lineBuffer[i] == '#') { + // check if the comment contains any flags ("#, ") and + // then whether the flags contain "fuzzy" + if (strstart(lineBuffer, "#, ") && strstr(lineBuffer, "fuzzy")) + styler.ColourTo(endPos, SCE_PO_FUZZY); + else + styler.ColourTo(endPos, SCE_PO_COMMENT); + } else { + if (lineBuffer[0] == '"') { + // line continuation, use previous style + styler.ColourTo(endPos, state); + return; + // this implicitly also matches "msgid_plural" + } else if (strstart(lineBuffer, "msgid")) { + state_start = SCE_PO_MSGID; + state = SCE_PO_MSGID_TEXT; + } else if (strstart(lineBuffer, "msgstr")) { + state_start = SCE_PO_MSGSTR; + state = SCE_PO_MSGSTR_TEXT; + } else if (strstart(lineBuffer, "msgctxt")) { + state_start = SCE_PO_MSGCTXT; + state = SCE_PO_MSGCTXT_TEXT; + } + if (state_start != SCE_PO_DEFAULT) { + // find the next space + while ((i < lengthLine) && ! isspacechar(lineBuffer[i])) + i++; + styler.ColourTo(startLine + i - 1, state_start); + styler.ColourTo(startLine + i, SCE_PO_DEFAULT); + styler.ColourTo(endPos, state); + } + } + } else { + styler.ColourTo(endPos, SCE_PO_DEFAULT); + } +} + +static void ColourisePoDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) { + char lineBuffer[1024]; + styler.StartAt(startPos); + styler.StartSegment(startPos); + unsigned int linePos = 0; + unsigned int startLine = startPos; + for (unsigned int i = startPos; i < startPos + length; i++) { + lineBuffer[linePos++] = styler[i]; + if (AtEOL(styler, i) || (linePos >= sizeof(lineBuffer) - 1)) { + // End of line (or of line buffer) met, colourise it + lineBuffer[linePos] = '\0'; + ColourisePoLine(lineBuffer, linePos, startLine, i, styler); + linePos = 0; + startLine = i + 1; + } + } + if (linePos > 0) { // Last line does not have ending characters + ColourisePoLine(lineBuffer, linePos, startLine, startPos + length - 1, styler); + } +} static void ColourisePropsLine( char *lineBuffer, @@ -815,10 +890,6 @@ static void ColouriseMakeDoc(unsigned int startPos, int length, int, WordList *[ } } -static bool strstart(const char *haystack, const char *needle) { - return strncmp(haystack, needle, strlen(needle)) == 0; -} - static int RecogniseErrorListLine(const char *lineBuffer, unsigned int lengthLine, int &startValue) { if (lineBuffer[0] == '>') { // Command or return status @@ -1170,6 +1241,7 @@ static void ColouriseNullDoc(unsigned int startPos, int length, int, WordList *[ LexerModule lmBatch(SCLEX_BATCH, ColouriseBatchDoc, "batch", 0, batchWordListDesc); LexerModule lmDiff(SCLEX_DIFF, ColouriseDiffDoc, "diff", FoldDiffDoc, emptyWordListDesc); +LexerModule lmPo(SCLEX_PO, ColourisePoDoc, "po", 0, emptyWordListDesc); LexerModule lmProps(SCLEX_PROPERTIES, ColourisePropsDoc, "props", FoldPropsDoc, emptyWordListDesc); LexerModule lmMake(SCLEX_MAKEFILE, ColouriseMakeDoc, "makefile", 0, emptyWordListDesc); LexerModule lmErrorList(SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist", 0, emptyWordListDesc); diff --git a/scintilla/include/SciLexer.h b/scintilla/include/SciLexer.h index ef2c33e3..7fc8a6cf 100644 --- a/scintilla/include/SciLexer.h +++ b/scintilla/include/SciLexer.h @@ -102,6 +102,7 @@ #define SCLEX_MAGIK 87 #define SCLEX_POWERSHELL 88 #define SCLEX_OMS 89 +#define SCLEX_PO 90 #define SCLEX_AUTOMATIC 1000 #define SCE_P_DEFAULT 0 #define SCE_P_COMMENTLINE 1 @@ -1234,6 +1235,15 @@ #define SCE_POWERSHELL_KEYWORD 8 #define SCE_POWERSHELL_CMDLET 9 #define SCE_POWERSHELL_ALIAS 10 +#define SCE_PO_DEFAULT 0 +#define SCE_PO_COMMENT 1 +#define SCE_PO_MSGID 2 +#define SCE_PO_MSGID_TEXT 3 +#define SCE_PO_MSGSTR 4 +#define SCE_PO_MSGSTR_TEXT 5 +#define SCE_PO_MSGCTXT 6 +#define SCE_PO_MSGCTXT_TEXT 7 +#define SCE_PO_FUZZY 8 #define SCLEX_ASP 29 #define SCLEX_PHP 30 /*--Autogenerated -- end of section automatically generated from Scintilla.iface*/ diff --git a/scintilla/include/Scintilla.iface b/scintilla/include/Scintilla.iface index 41c58078..7d9c4cb7 100644 --- a/scintilla/include/Scintilla.iface +++ b/scintilla/include/Scintilla.iface @@ -1997,6 +1997,7 @@ val SCLEX_ASYMPTOTE=85 val SCLEX_R=86 val SCLEX_MAGIK=87 val SCLEX_POWERSHELL=88 +val SCLEX_PO=90 # When a lexer specifies its language as SCLEX_AUTOMATIC it receives a # value assigned in sequence from SCLEX_AUTOMATIC+1. @@ -3294,6 +3295,17 @@ val SCE_POWERSHELL_IDENTIFIER=7 val SCE_POWERSHELL_KEYWORD=8 val SCE_POWERSHELL_CMDLET=9 val SCE_POWERSHELL_ALIAS=10 +# Lexical state for SCLEX_PO +lex Po=SCLEX_PO SCE_PO_ +val SCE_PO_DEFAULT=0 +val SCE_PO_COMMENT=1 +val SCE_PO_MSGID=2 +val SCE_PO_MSGID_TEXT=3 +val SCE_PO_MSGSTR=4 +val SCE_PO_MSGSTR_TEXT=5 +val SCE_PO_MSGCTXT=6 +val SCE_PO_MSGCTXT_TEXT=7 +val SCE_PO_FUZZY=8 # Events diff --git a/src/editor.c b/src/editor.c index 3f3bd29c..d5829edd 100644 --- a/src/editor.c +++ b/src/editor.c @@ -2793,6 +2793,9 @@ static gboolean is_comment_style(gint lexer, gint style) case SCLEX_PROPERTIES: return (style == SCE_PROPS_COMMENT); + case SCLEX_PO: + return (style == SCE_PO_COMMENT); + case SCLEX_LATEX: return (style == SCE_L_COMMENT); diff --git a/src/filetypes.c b/src/filetypes.c index 8548dad6..09f58e52 100644 --- a/src/filetypes.c +++ b/src/filetypes.c @@ -450,6 +450,17 @@ static void init_builtin_filetypes(void) ft->comment_close = NULL; ft->group = GEANY_FILETYPE_GROUP_MISC; +#define PO + ft = filetypes[GEANY_FILETYPES_PO]; + ft->lang = -2; + ft->name = g_strdup("Po"); + ft->title = g_strdup(_("Gettext translation file")); + ft->extension = g_strdup("po"); + ft->pattern = utils_strv_new("*.po", "*.pot", NULL); + ft->comment_open = g_strdup("#"); + ft->comment_close = NULL; + ft->group = GEANY_FILETYPE_GROUP_MISC; + #define HAXE ft = filetypes[GEANY_FILETYPES_HAXE]; ft->lang = 27; diff --git a/src/filetypes.h b/src/filetypes.h index dccbced1..bddeadaf 100644 --- a/src/filetypes.h +++ b/src/filetypes.h @@ -78,6 +78,7 @@ typedef enum GEANY_FILETYPES_LATEX, GEANY_FILETYPES_REST, GEANY_FILETYPES_SQL, + GEANY_FILETYPES_PO, GEANY_FILETYPES_NONE, /* must be last filetype */ GEANY_MAX_BUILT_IN_FILETYPES /* Use filetypes_array->len instead */ diff --git a/src/highlighting.c b/src/highlighting.c index c2210151..719ad559 100644 --- a/src/highlighting.c +++ b/src/highlighting.c @@ -2027,6 +2027,47 @@ static void styleset_css(ScintillaObject *sci) } +static void styleset_po_init(gint ft_id, GKeyFile *config, GKeyFile *config_home) +{ + new_style_array(GEANY_FILETYPES_PO, 9); + get_keyfile_hex(config, config_home, "styling", "default", "0x7f0000", "0xffffff", "false", &style_sets[GEANY_FILETYPES_PO].styling[0]); + get_keyfile_hex(config, config_home, "styling", "comment", "0x808080", "0xffffff", "false", &style_sets[GEANY_FILETYPES_PO].styling[1]); + get_keyfile_hex(config, config_home, "styling", "msgid", "0x00007f", "0xffffff", "true", &style_sets[GEANY_FILETYPES_PO].styling[2]); + get_keyfile_hex(config, config_home, "styling", "msgid_text", "0x00007f", "0xffffff", "false", &style_sets[GEANY_FILETYPES_PO].styling[3]); + get_keyfile_hex(config, config_home, "styling", "msgstr", "0x7f0000", "0xffffff", "true", &style_sets[GEANY_FILETYPES_PO].styling[4]); + get_keyfile_hex(config, config_home, "styling", "msgstr_text", "0x7f0000", "0xffffff", "false", &style_sets[GEANY_FILETYPES_PO].styling[5]); + get_keyfile_hex(config, config_home, "styling", "msgctxt", "0x007f00", "0xffffff", "true", &style_sets[GEANY_FILETYPES_PO].styling[6]); + get_keyfile_hex(config, config_home, "styling", "msgctxt_text", "0x007f00", "0xffffff", "false", &style_sets[GEANY_FILETYPES_PO].styling[7]); + get_keyfile_hex(config, config_home, "styling", "fuzzy", "0xffa500", "0xffffff", "true", &style_sets[GEANY_FILETYPES_PO].styling[8]); + + style_sets[GEANY_FILETYPES_PO].keywords = NULL; + + get_keyfile_wordchars(config, config_home, + &style_sets[GEANY_FILETYPES_PO].wordchars); +} + + +static void styleset_po(ScintillaObject *sci) +{ + const filetype_id ft_id = GEANY_FILETYPES_PO; + + styleset_common(sci, 5, ft_id); + + apply_filetype_properties(sci, SCLEX_PO, ft_id); + + set_sci_style(sci, STYLE_DEFAULT, GEANY_FILETYPES_PO, 0); + set_sci_style(sci, SCE_PO_DEFAULT, GEANY_FILETYPES_PO, 0); + set_sci_style(sci, SCE_PO_COMMENT, GEANY_FILETYPES_PO, 1); + set_sci_style(sci, SCE_PO_MSGID, GEANY_FILETYPES_PO, 2); + set_sci_style(sci, SCE_PO_MSGID_TEXT, GEANY_FILETYPES_PO, 3); + set_sci_style(sci, SCE_PO_MSGSTR, GEANY_FILETYPES_PO, 4); + set_sci_style(sci, SCE_PO_MSGSTR_TEXT, GEANY_FILETYPES_PO, 5); + set_sci_style(sci, SCE_PO_MSGCTXT, GEANY_FILETYPES_PO, 6); + set_sci_style(sci, SCE_PO_MSGCTXT_TEXT, GEANY_FILETYPES_PO, 7); + set_sci_style(sci, SCE_PO_FUZZY, GEANY_FILETYPES_PO, 8); +} + + static void styleset_conf_init(gint ft_id, GKeyFile *config, GKeyFile *config_home) { new_style_array(GEANY_FILETYPES_CONF, 6); @@ -3102,6 +3143,7 @@ void highlighting_init_styles(gint filetype_idx, GKeyFile *config, GKeyFile *con init_styleset_case(GEANY_FILETYPES_PASCAL, pascal); init_styleset_case(GEANY_FILETYPES_PERL, perl); init_styleset_case(GEANY_FILETYPES_PHP, php); + init_styleset_case(GEANY_FILETYPES_PO, po); init_styleset_case(GEANY_FILETYPES_PYTHON, python); init_styleset_case(GEANY_FILETYPES_R, r); init_styleset_case(GEANY_FILETYPES_RUBY, ruby); @@ -3157,6 +3199,7 @@ void highlighting_set_styles(ScintillaObject *sci, gint filetype_idx) styleset_case(GEANY_FILETYPES_PASCAL, pascal); styleset_case(GEANY_FILETYPES_PERL, perl); styleset_case(GEANY_FILETYPES_PHP, php); + styleset_case(GEANY_FILETYPES_PO, po); styleset_case(GEANY_FILETYPES_PYTHON, python); styleset_case(GEANY_FILETYPES_R, r); styleset_case(GEANY_FILETYPES_RUBY, ruby); diff --git a/src/plugindata.h b/src/plugindata.h index 608aafab..ea11d648 100644 --- a/src/plugindata.h +++ b/src/plugindata.h @@ -41,7 +41,7 @@ enum { /** The Application Programming Interface (API) version, incremented * whenever any plugin data types are modified or appended to. */ - GEANY_API_VERSION = 97, + GEANY_API_VERSION = 98, /** The Application Binary Interface (ABI) version, incremented whenever * existing fields in the plugin data types have to be changed or reordered. */ diff --git a/src/templates.c b/src/templates.c index e104e89b..e454e720 100644 --- a/src/templates.c +++ b/src/templates.c @@ -534,6 +534,7 @@ static gchar *make_comment_block(const gchar *comment_text, gint filetype_idx, g case GEANY_FILETYPES_TCL: case GEANY_FILETYPES_OMS: case GEANY_FILETYPES_CONF: + case GEANY_FILETYPES_PO: { line_prefix = "#"; break;