[geany/geany] 21dfbd: Merge branch 'master' of https://github.com/geany/geany

Giuseppe Penone git-noreply at xxxxx
Sat Feb 20 21:34:39 UTC 2016


Branch:      refs/heads/master
Author:      Giuseppe Penone <giuspen at gmail.com>
Committer:   Giuseppe Penone <giuspen at gmail.com>
Date:        Sat, 20 Feb 2016 21:34:39 UTC
Commit:      21dfbd0edf2f739379655cf32bc537de5385d919
             https://github.com/geany/geany/commit/21dfbd0edf2f739379655cf32bc537de5385d919

Log Message:
-----------
Merge branch 'master' of https://github.com/geany/geany


Modified Paths:
--------------
    NEWS
    data/filetypes.rust
    data/geany.glade
    doc/geany.txt
    po/de.po
    po/ja.po
    po/ko.po
    po/lt.po
    po/pt.po
    scintilla/gtk/ScintillaGTK.cxx
    scintilla/scintilla_changes.patch
    scripts/plugin_test.c
    src/document.c
    src/documentprivate.h
    src/editor.c
    src/filetypes.c
    src/keybindings.c
    src/keybindings.h
    src/libmain.c
    src/sidebar.c
    src/spawn.c
    src/stash.c
    src/stash.h
    src/symbols.c
    src/tools.c
    tagmanager/ctags/c.c
    tagmanager/ctags/get.c
    tagmanager/ctags/get.h
    tagmanager/ctags/read.c
    tagmanager/ctags/read.h
    tagmanager/src/tm_source_file.c
    tagmanager/src/tm_source_file.h
    tagmanager/src/tm_tag.c
    tagmanager/src/tm_tag.h
    tagmanager/src/tm_workspace.c
    tagmanager/src/tm_workspace.h
    tests/ctags/Makefile.am
    tests/ctags/bit_field.c.tags
    tests/ctags/bug1799340.cpp.tags
    tests/ctags/bug1907083.cpp.tags
    tests/ctags/bug1924919.cpp.tags
    tests/ctags/c-digraphs.c.tags
    tests/ctags/c-trigraphs.c.tags
    tests/ctags/cxx11-raw-strings.cpp
    tests/ctags/cxx11-raw-strings.cpp.tags
    tests/ctags/indexer.cs.tags
    tests/ctags/interface_indexers.cs.tags
    tests/ctags/keyword_const.cs.tags
    tests/ctags/keyword_virtual.cs.tags
    tests/ctags/keyword_volatile.cs.tags
    tests/ctags/simple.d.tags
    tests/ctags/var-and-return-type.cpp
    tests/ctags/var-and-return-type.cpp.tags

Modified: NEWS
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -1,7 +1,7 @@
 Geany 1.27 (unreleased)
 
     Internationalization
-    * Updated translations: it
+    * Updated translations: de, it, ja, lt, pt
 
 
 Geany 1.26 (November 15, 2015)


Modified: data/filetypes.rust
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -60,7 +60,7 @@ context_action_cmd=
 [indentation]
 #width=4
 # 0 is spaces, 1 is tabs, 2 is tab & spaces
-#type=1
+#type=0
 
 [build-menu]
 FT_00_LB=Compile


Modified: data/geany.glade
8 lines changed, 4 insertions(+), 4 deletions(-)
===================================================================
@@ -500,7 +500,7 @@
     </child>
     <child>
       <object class="GtkImageMenuItem" id="goto_tag_definition2">
-        <property name="label" translatable="yes">Go to _Tag Definition</property>
+        <property name="label" translatable="yes">Go to Symbol Defini_tion</property>
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="use_underline">True</property>
@@ -7283,7 +7283,7 @@
                                   <object class="GtkMenuItem" id="goto_tag_definition1">
                                     <property name="visible">True</property>
                                     <property name="can_focus">False</property>
-                                    <property name="label" translatable="yes">Go to _Tag Definition</property>
+                                    <property name="label" translatable="yes">Go to Symbol Defini_tion</property>
                                     <property name="use_underline">True</property>
                                     <signal name="activate" handler="on_goto_tag_definition1" swapped="no"/>
                                   </object>
@@ -7292,7 +7292,7 @@
                                   <object class="GtkMenuItem" id="goto_tag_declaration1">
                                     <property name="visible">True</property>
                                     <property name="can_focus">False</property>
-                                    <property name="label" translatable="yes">Go to T_ag Declaration</property>
+                                    <property name="label" translatable="yes">Go to Symbol Decl_aration</property>
                                     <property name="use_underline">True</property>
                                     <signal name="activate" handler="on_goto_tag_declaration1" swapped="no"/>
                                   </object>
@@ -8049,7 +8049,7 @@
                           <object class="GtkMenuItem" id="load_tags1">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="label" translatable="yes">Load Ta_gs...</property>
+                            <property name="label" translatable="yes">Load Ta_gs File...</property>
                             <property name="use_underline">True</property>
                             <signal name="activate" handler="on_load_tags1_activate" swapped="no"/>
                           </object>


Modified: doc/geany.txt
177 lines changed, 88 insertions(+), 89 deletions(-)
===================================================================
@@ -342,7 +342,7 @@ Short option  Long option              Function
 -g            --generate-tags          Generate a global tags file (see
                                        `Generating a global tags file`_).
 
--P            --no-preprocessing       Don't preprocess C/C++ files when generating tags.
+-P            --no-preprocessing       Don't preprocess C/C++ files when generating tags file.
 
 -i            --new-instance           Do not open files in a running instance, force opening
                                        a new instance. Only available if Geany was compiled
@@ -894,8 +894,8 @@ To ease navigation in source files and especially between
 different files, Geany lets you jump between different navigation
 points. Currently, this works for the following:
 
-* `Go to tag declaration`_
-* `Go to tag definition`_
+* `Go to symbol declaration`_
+* `Go to symbol definition`_
 * Symbol list items
 * Build errors
 * Message items
@@ -981,7 +981,7 @@ Autocompletion
 ^^^^^^^^^^^^^^
 
 Geany can offer a list of possible completions for symbols defined in the
-tags and for all words in a document.
+tags files and for all words in open documents.
 
 The autocompletion list for symbols is presented when the first few
 characters of the symbol are typed (configurable, see `Editor Completions
@@ -1038,7 +1038,7 @@ When you type ``foo.`` it will show an autocompletion list with 'i' and
 'c' symbols.
 
 It only works for languages that set parent scope names for e.g. struct
-members. Currently this means C-like languages. The C tag parser only
+members. Currently this means C-like languages. The C parser only
 parses global scopes, so this won't work for structs or objects declared
 in local scope.
 
@@ -1191,8 +1191,8 @@ and the editor window's popup menu:
 * Find usage
 * Find in files
 * Replace
-* Go to tag definition
-* Go to tag declaration
+* Go to symbol definition
+* Go to symbol declaration
 * Go to line
 
 See also `Search`_ preferences.
@@ -1415,27 +1415,27 @@ documents. *Replace All In Selection* will replace all matching text
 in the current selection of the current document.
 
 
-Go to tag definition
-^^^^^^^^^^^^^^^^^^^^
+Go to symbol definition
+^^^^^^^^^^^^^^^^^^^^^^^
 
-If the current word or selection is the name of a tag definition
-(e.g. a function name) and the file containing the tag definition is
+If the current word or selection is the name of a symbol definition
+(e.g. a function name) and the file containing the symbol definition is
 open, this command will switch to that file and go to the
 corresponding line number. The current word is either the word
 nearest the edit cursor, or the word underneath the popup menu click
 position when the popup menu is used.
 
 .. note::
-    If the corresponding tag is on the current line, Geany will first
-    look for a tag declaration instead, as this is more useful.
-    Likewise *Go to tag declaration* will search for a tag definition
+    If the corresponding symbol is on the current line, Geany will first
+    look for a symbol declaration instead, as this is more useful.
+    Likewise *Go to symbol declaration* will search for a symbol definition
     first in this case also.
 
 
-Go to tag declaration
-^^^^^^^^^^^^^^^^^^^^^
+Go to symbol declaration
+^^^^^^^^^^^^^^^^^^^^^^^^
 
-Like *Go to tag definition*, but for a forward declaration such as a
+Like *Go to symbol definition*, but for a forward declaration such as a
 C function prototype or ``extern`` declaration instead of a function
 body.
 
@@ -1596,46 +1596,43 @@ translations, e.g.::
     key[de]=Hallo
     key[fr_FR]=Bonjour
 
-Tags
-----
-
-Tags are information that relates symbols in a program with the
-source file location of the declaration and definition.
+Symbols and tags files
+----------------------
 
-Geany has built-in functionality for generating tag information (aka
-"workspace tags") for supported filetypes when you open a file.  You
-can also have Geany automatically load external tag files (aka "global
-tags files") upon startup, or manually using *Tools --> Load Tags*.
+Upon opening, files of supported filetypes are parsed to extract the symbol
+information (aka "workspace symbols"). You can also have Geany automatically
+load external files containing the symbol information (aka "global
+tags files") upon startup, or manually using *Tools --> Load Tags File*.
 
-Geany uses its own tag file format, similar to what ``ctags`` uses
+Geany uses its own tags file format, similar to what ``ctags`` uses
 (but is incompatible with ctags). You use Geany to generate global
 tags files, as described below.
 
 
-Workspace tags
-^^^^^^^^^^^^^^
+Workspace symbols
+^^^^^^^^^^^^^^^^^
 
-Tags for each document are parsed whenever a file is loaded, saved or
+Each document is parsed for symbols whenever a file is loaded, saved or
 modified (see *Symbol list update frequency* preference in the `Editor
 Completions preferences`_). These are shown in the Symbol list in the
-Sidebar. These tags are also used for autocompletion of symbols and calltips
+Sidebar. These symbols are also used for autocompletion and calltips
 for all documents open in the current session that have the same filetype.
 
-The *Go to Tag* commands can be used with all workspace tags. See
-`Go to tag definition`_.
+The *Go to Symbol* commands can be used with all workspace symbols. See
+`Go to symbol definition`_.
 
 
-Global tags
-^^^^^^^^^^^
+Global tags files
+^^^^^^^^^^^^^^^^^
 
-Global tags are used to provide autocompletion of symbols and calltips
-without having to open the corresponding source files. This is intended
+Global tags files are used to provide symbols for autocompletion and calltips
+without having to open the source files containing these symbols. This is intended
 for library APIs, as the tags file only has to be updated when you upgrade
 the library.
 
 You can load a custom global tags file in two ways:
 
-* Using the *Load Tags* command in the Tools menu.
+* Using the *Load Tags File* command in the Tools menu.
 * By moving or symlinking tags files to the ``tags`` subdirectory of
   one of the `configuration file paths`_ before starting Geany.
 
@@ -1645,15 +1642,16 @@ the format::
     name.lang_ext.tags
 
 *lang_ext* is one of the extensions set for the filetype associated
-with the tags. See the section called `Filetype extensions`_ for
+with the tags parser. See the section called `Filetype extensions`_ for
 more information.
 
 
 Default global tags files
 `````````````````````````
 
-For some languages, a list of global tags is loaded when the
-corresponding filetype is first used. Currently these are for:
+Some global tags files are distributed with Geany and will be loaded
+automatically when the corresponding filetype is first used. Currently
+this includes global tags files for these languages:
 
 * C
 * Pascal
@@ -1681,32 +1679,32 @@ might fail.
 
 
 The Tagmanager format is a bit more complex and is used for files
-created by the ``geany -g`` command. There is one tag per line.
-Different tag attributes like the return value or the argument list
+created by the ``geany -g`` command. There is one symbol per line.
+Different symbol attributes like the return value or the argument list
 are separated with different characters indicating the type of the
-following argument.  This is the more complete and recommended tag
+following argument.  This is the more complete and recommended tags file
 format.
 
 Pipe-separated format
 *********************
 The Pipe-separated format is easier to read and write.
-There is one tag per line and different tag attributes are separated
+There is one symbol per line and different symbol attributes are separated
 by the pipe character (``|``). A line looks like::
 
     basename|string|(string path [, string suffix])|
 
-| The first field is the tag name (usually a function name).
+| The first field is the symbol name (usually a function name).
 | The second field is the type of the return value.
-| The third field is the argument list for this tag.
-| The fourth field is the description for this tag but
+| The third field is the argument list for this symbol.
+| The fourth field is the description for this symbol but
   currently unused and should be left empty.
 
-Except for the first field (tag name), all other field can be left
+Except for the first field (symbol name), all other field can be left
 empty but the pipe separator must appear for them.
 
-You can easily write your own global tag files using this format.
+You can easily write your own global tags files using this format.
 Just save them in your tags directory, as described earlier in the
-section `Global tags`_.
+section `Global tags files`_.
 
 CTags format
 ************
@@ -1724,12 +1722,12 @@ Generating a global tags file
 You can generate your own global tags files by parsing a list of
 source files. The command is::
 
-    geany -g [-P] <Tag File> <File list>
+    geany -g [-P] <Tags File> <File list>
 
-* Tag File filename should be in the format described earlier --
-  see the section called `Global tags`_.
+* Tags File filename should be in the format described earlier --
+  see the section called `Global tags files`_.
 * File list is a list of filenames, each with a full path (unless
-  you are generating C/C++ tags and have set the CFLAGS environment
+  you are generating C/C++ tags files and have set the CFLAGS environment
   variable appropriately).
 * ``-P`` or ``--no-preprocessing`` disables using the C pre-processor
   to process ``#include`` directives for C/C++ source files. Use this
@@ -1742,17 +1740,17 @@ Example for the wxD library for the D programming language::
     geany -g wxd.d.tags /home/username/wxd/wx/*.d
 
 
-Generating C/C++ tag files
-**************************
+Generating C/C++ tags files
+***************************
 You may need to first setup the `C ignore.tags`_ file.
 
-For C/C++ tag files gcc is required by default, so that header files
+For C/C++ tags files gcc is required by default, so that header files
 can be preprocessed to include any other headers they depend upon. If
 you do not want this, use the ``-P`` option described above.
 
 For preprocessing, the environment variable CFLAGS should be set with
 appropriate ``-I/path`` include paths. The following example works with
-the bash shell, generating tags for the GnomeUI library::
+the bash shell, generating a tags file for the GnomeUI library::
 
     CFLAGS=`pkg-config --cflags libgnomeui-2.0` geany -g gnomeui.c.tags \
     /usr/include/libgnomeui-2.0/gnome.h
@@ -1761,8 +1759,8 @@ You can adapt this command to use CFLAGS and header files appropriate
 for whichever libraries you want.
 
 
-Generating tag files on Windows
-*******************************
+Generating tags files on Windows
+********************************
 This works basically the same as on other platforms::
 
     "c:\program files\geany\bin\geany" -g c:\mytags.php.tags c:\code\somefile.php
@@ -1771,12 +1769,12 @@ This works basically the same as on other platforms::
 C ignore.tags
 ^^^^^^^^^^^^^
 
-You can ignore certain tags for C-based languages if they would lead
+You can ignore certain symbols for C-based languages if they would lead
 to wrong parsing of the code. Use the *Tools->Configuration
 Files->ignore.tags* menu item to open the user ``ignore.tags`` file.
 See also `Configuration file paths`_.
 
-List all tag names you want to ignore in this file, separated by spaces
+List all symbol names you want to ignore in this file, separated by spaces
 and/or newlines.
 
 Example::
@@ -1790,7 +1788,7 @@ This will parse code like:
 ``gchar **utils_strv_new(const gchar *first, ...)
 G_GNUC_NULL_TERMINATED;``
 
-More detailed information about ignore tags usage from the Exuberant Ctags
+More detailed information about ignore.tags usage from the Exuberant Ctags
 manual page:
 
     Specifies a list of identifiers which are to be specially handled
@@ -2222,7 +2220,7 @@ Autocomplete symbols
 Autocomplete all words in document
     When you start to type a word, Geany will search the whole document for
     words starting with the typed part to complete it, assuming there
-    are no tag names to show.
+    are no symbol names to show.
 
 Drop rest of word on completion
     Remove any word part to the right of the cursor when choosing a
@@ -2241,7 +2239,7 @@ Max. symbol name suggestions
 Symbol list update frequency
     The minimum delay (in milliseconds) between two symbol list updates.
 
-    This option determines how frequently the tag list is updated for the
+    This option determines how frequently the symbol list is updated for the
     current document. The smaller the delay, the more up-to-date the symbol
     list (and then the completions); but rebuilding the symbol list has a
     cost in performance, especially with large files.
@@ -3420,9 +3418,9 @@ Scroll up by one line           Alt-Up                    Scrolls the view.
 Scroll down by one line         Alt-Down                  Scrolls the view.
 
 Complete word                   Ctrl-Space                Shows the autocompletion list. If already showing
-                                                          tag completion, it shows document word completion
+                                                          symbol completion, it shows document word completion
                                                           instead, even if it is not enabled for automatic
-                                                          completion. Likewise if no tag suggestions are
+                                                          completion. Likewise if no symbol suggestions are
                                                           available, it shows document word completion.
 
 Show calltip                    Ctrl-Shift-Space          Shows a calltip for the current function or
@@ -3558,7 +3556,7 @@ Smart line indent                                         Indents the current li
 
 Send to Custom Command 1 (2,3)  Ctrl-1 (2,3)              Passes the current selection to a configured
                                                           external command (available for the first
-                                                          three configured commands, see
+                                                          9 configured commands, see
                                                           `Sending text through custom commands`_ for
                                                           details).
 
@@ -3656,11 +3654,11 @@ Goto next marker                Ctrl-.                    Goto the next marker i
 
 Goto previous marker            Ctrl-,                    Goto the previous marker in the current document.
 
-Go to tag definition            Ctrl-T                    Jump to the definition of the current word or
-                                                          selection. See `Go to tag definition`_.
+Go to symbol definition         Ctrl-T                    Jump to the definition of the current word or
+                                                          selection. See `Go to symbol definition`_.
 
-Go to tag declaration           Ctrl-Shift-T              Jump to the declaration of the current word or
-                                                          selection. See `Go to tag declaration`_.
+Go to symbol declaration        Ctrl-Shift-T              Jump to the declaration of the current word or
+                                                          selection. See `Go to symbol declaration`_.
 
 Go to Start of Line             Home                      Move the caret to the start of the line.
                                                           Behaves differently if smart_home_key_ is set.
@@ -3786,7 +3784,7 @@ Fold all                                                  Folds all contractible
 
 Unfold all                                                Unfolds all contracted code blocks.
 
-Reload symbol list                   Ctrl-Shift-R         Reloads the tag/symbol list.
+Reload symbol list                   Ctrl-Shift-R         Reloads the symbol list.
 
 Toggle Line wrapping                                      Enables or disables wrapping of long lines.
 
@@ -4033,7 +4031,7 @@ support for the following has been implemented:
 * `Filetype group membership`_.
 * Reading filetype settings in the ``[settings]`` section, including:
     * Using an existing syntax highlighting lexer (`lexer_filetype`_ key).
-    * Using an existing tag parser (`tag_parser`_ key).
+    * Using an existing tags parser (`tag_parser`_ key).
 * Build commands (``[build-menu]`` section).
 * Loading global tags files (sharing the ``tag_parser`` filetype's namespace).
 
@@ -4266,12 +4264,12 @@ lexer_filetype
 symbol_list_sort_mode
     What the default symbol list sort order should be.
 
-    =====   =====================================
+    =====   ========================================
     Value   Meaning
-    =====   =====================================
-    0       Sort tags by name
-    1       Sort tags by appearance (line number)
-    =====   =====================================
+    =====   ========================================
+    0       Sort symbols by name
+    1       Sort symbols by appearance (line number)
+    =====   ========================================
 
 .. _xml_indent_tags:
 
@@ -4316,15 +4314,16 @@ As of Geany 0.19 this section is supplemented by the `[build-menu] section`_.
 Values that are set in the [build-menu] section will override those in this section.
 
 error_regex
-    This is a regular expression to parse a filename
-    and line number from build output. If undefined, Geany will fall
-    back to its default error message parsing.
+    This is a Perl-compatible regular expression (PCRE) to parse a filename
+    (absolute or relative) and line number from the build output.
+    If undefined, Geany will fall back to its default error message parsing.
 
-    Only the first two matches will be read by Geany. Geany will look for
-    a match that is purely digits, and use this for the line number. The
-    remaining match will be used as the filename.
+    Only the first two match groups will be read by Geany. These groups can
+    occur in any order: the match group consisting of only digits will be used
+    as the line number, and the other group as the filename.  In no group
+    consists of only digits, the match will fail.
 
-    *Example:* ``error_regex=(.+):([0-9]+):[0-9]+``
+    *Example:* ``error_regex=^(.+):([0-9]+):[0-9]+``
 
     This will parse a message such as:
     ``test.py:7:24: E202 whitespace before ']'``
@@ -4591,7 +4590,7 @@ translucency
     *Example:* ``translucency=256;256;false;false``
 
 marker_line
-    The style for a highlighted line (e.g when using Goto line or goto tag).
+    The style for a highlighted line (e.g when using Goto line or goto symbol).
     The foreground color (first argument) is only used when the Markers margin
     is enabled (see View menu).
 
@@ -5334,7 +5333,7 @@ Editor
 * Alt-scroll wheel moves up/down a page.
 * Ctrl-scroll wheel zooms in/out.
 * Shift-scroll wheel scrolls 8 characters right/left.
-* Ctrl-click on a word in a document to perform *Go to Tag Definition*.
+* Ctrl-click on a word in a document to perform *Go to Symbol Definition*.
 * Ctrl-click on a bracket/brace to perform *Go to Matching Brace*.
 
 Interface


Modified: po/de.po
1582 lines changed, 799 insertions(+), 783 deletions(-)
===================================================================
No diff available, check online


Modified: po/ja.po
1691 lines changed, 849 insertions(+), 842 deletions(-)
===================================================================
No diff available, check online


Modified: po/ko.po
2403 lines changed, 1092 insertions(+), 1311 deletions(-)
===================================================================
No diff available, check online


Modified: po/lt.po
37 lines changed, 19 insertions(+), 18 deletions(-)
===================================================================
@@ -8,8 +8,8 @@ msgstr ""
 "Project-Id-Version: Geany 1.25\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2015-11-01 19:03+0100\n"
-"PO-Revision-Date: 2014-04-06 08:42+0200\n"
-"Last-Translator: Algimantas Margevičius <algimantas at margevicius.lt>\n"
+"PO-Revision-Date: 2016-02-08 08:29+0200\n"
+"Last-Translator: Zygimantus <zygimantus at gmail.com>\n"
 "Language-Team: Lietuvių <>\n"
 "Language: lt\n"
 "MIME-Version: 1.0\n"
@@ -17,7 +17,7 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n"
 "%100<10 || n%100>=20) ? 1 : 2);\n"
-"X-Generator: Poedit 1.6.4\n"
+"X-Generator: Poedit 1.8.4\n"
 
 #: ../geany.desktop.in.h:1 ../data/geany.glade.h:338
 msgid "Geany"
@@ -2092,8 +2092,8 @@ msgstr "Projekto savybės"
 msgid "Filename:"
 msgstr "Failo vardas:"
 
-#: ../data/geany.glade.h:460 ../src/project.c:169 ../plugins/classbuilder.c:467
-#: ../plugins/classbuilder.c:477
+#: ../data/geany.glade.h:460 ../src/project.c:169
+#: ../plugins/classbuilder.c:467 ../plugins/classbuilder.c:477
 msgid "Name:"
 msgstr "Pavadinimas:"
 
@@ -2539,9 +2539,8 @@ msgid "Detect from file"
 msgstr "Aptikti iš failo"
 
 #: ../src/dialogs.c:225
-#, fuzzy
 msgid "Programming Languages"
-msgstr "_Programavimo kalbos"
+msgstr "Programavimo kalbos"
 
 #: ../src/dialogs.c:227
 #, fuzzy
@@ -2549,9 +2548,8 @@ msgid "Scripting Languages"
 msgstr "_Scenarijų kalbos"
 
 #: ../src/dialogs.c:229
-#, fuzzy
 msgid "Markup Languages"
-msgstr "_Išvaizdos kalbos"
+msgstr "Žymėjimo kalbos"
 
 #: ../src/dialogs.c:307
 msgid "_More Options"
@@ -2776,7 +2774,7 @@ msgstr ", tik skaitymui"
 
 #: ../src/document.c:1627
 msgid "Discard history"
-msgstr ""
+msgstr "Išvalyti istoriją"
 
 #: ../src/document.c:1628
 msgid ""
@@ -2846,9 +2844,8 @@ msgid "Failed to close file '%s': fclose() failed: %s"
 msgstr "Nepavyko užverti failo „%s“: fclose() klaida: %s"
 
 #: ../src/document.c:2058 ../src/document.c:3589
-#, fuzzy
 msgid "_Overwrite"
-msgstr "Perrašyti?"
+msgstr "Perrašyti"
 
 #: ../src/document.c:2060 ../src/document.c:3592
 #, fuzzy, c-format
@@ -3893,7 +3890,7 @@ msgstr "Rasti failo „%s“ nepavyko - bandomas dabartinis dokumento kelias."
 
 #: ../src/msgwindow.c:1109
 msgid "The document has been closed."
-msgstr ""
+msgstr "Dokumentas buvo uždarytas."
 
 #: ../src/notebook.c:199
 msgid "Switch to Document"
@@ -3931,6 +3928,9 @@ msgid ""
 "Author(s):\t%s\n"
 "Filename:\t%s"
 msgstr ""
+"Versija:\t%s\n"
+"Autorius(-iai):\t%s\n"
+"Failas:\t%s"
 
 #: ../src/plugins.c:1630
 msgid "No plugins available."
@@ -5326,15 +5326,15 @@ msgstr "Unix (LF)"
 
 #: ../src/utils.c:386
 msgid "CRLF"
-msgstr ""
+msgstr "CRLF"
 
 #: ../src/utils.c:387
 msgid "CR"
-msgstr ""
+msgstr "CR"
 
 #: ../src/utils.c:388
 msgid "LF"
-msgstr ""
+msgstr "LF"
 
 #: ../src/vte.c:489
 #, c-format
@@ -5483,8 +5483,9 @@ msgstr "HTML simboliai"
 msgid "Inserts HTML character entities like '&'."
 msgstr "Įterpia HTML simbolių atitikmenis tokius kaip „&“."
 
-#: ../plugins/htmlchars.c:40 ../plugins/export.c:38 ../plugins/filebrowser.c:51
-#: ../plugins/saveactions.c:44 ../plugins/splitwindow.c:35
+#: ../plugins/htmlchars.c:40 ../plugins/export.c:38
+#: ../plugins/filebrowser.c:51 ../plugins/saveactions.c:44
+#: ../plugins/splitwindow.c:35
 msgid "The Geany developer team"
 msgstr "Geany kūrėjų komanda"
 


Modified: po/pt.po
1798 lines changed, 903 insertions(+), 895 deletions(-)
===================================================================
No diff available, check online


Modified: scintilla/gtk/ScintillaGTK.cxx
3 lines changed, 3 insertions(+), 0 deletions(-)
===================================================================
@@ -3052,6 +3052,7 @@ sptr_t scintilla_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_
 	return psci->WndProc(iMessage, wParam, lParam);
 }
 
+GEANY_API_SYMBOL
 sptr_t scintilla_object_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
 	return scintilla_send_message(sci, iMessage, wParam, lParam);
 }
@@ -3093,6 +3094,7 @@ GType scintilla_get_type() {
 	return scintilla_type;
 }
 
+GEANY_API_SYMBOL
 GType scintilla_object_get_type() {
 	return scintilla_get_type();
 }
@@ -3210,6 +3212,7 @@ GtkWidget* scintilla_new() {
 	return widget;
 }
 
+GEANY_API_SYMBOL
 GtkWidget *scintilla_object_new() {
 	return scintilla_new();
 }


Modified: scintilla/scintilla_changes.patch
28 lines changed, 25 insertions(+), 3 deletions(-)
===================================================================
@@ -4,7 +4,7 @@ diff --git scintilla/gtk/ScintillaGTK.cxx scintilla/gtk/ScintillaGTK.cxx
 index 0871ca2..49dc278 100644
 --- scintilla/gtk/ScintillaGTK.cxx
 +++ scintilla/gtk/ScintillaGTK.cxx
-@@ -3046,6 +3046,7 @@ sptr_t ScintillaGTK::DirectFunction(
+@@ -3046,11 +3046,13 @@ sptr_t ScintillaGTK::DirectFunction(
  }
  
  /* legacy name for scintilla_object_send_message */
@@ -12,7 +12,13 @@ index 0871ca2..49dc278 100644
  sptr_t scintilla_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
  	ScintillaGTK *psci = static_cast<ScintillaGTK *>(sci->pscin);
  	return psci->WndProc(iMessage, wParam, lParam);
-@@ -3062,6 +3062,7 @@ extern void Platform_Initialise();
+ }
+ 
++GEANY_API_SYMBOL
+ sptr_t scintilla_object_send_message(ScintillaObject *sci, unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
+ 	return scintilla_send_message(sci, iMessage, wParam, lParam);
+ }
+@@ -3062,6 +3064,7 @@ extern void Platform_Initialise();
  extern void Platform_Finalise();
  
  /* legacy name for scintilla_object_get_type */
@@ -20,7 +26,15 @@ index 0871ca2..49dc278 100644
  GType scintilla_get_type() {
  	static GType scintilla_type = 0;
  	try {
-@@ -3200,6 +3200,7 @@ static void scintilla_init(ScintillaObject *sci) {
+@@ -3091,6 +3094,7 @@ GType scintilla_get_type() {
+ 	return scintilla_type;
+ }
+ 
++GEANY_API_SYMBOL
+ GType scintilla_object_get_type() {
+ 	return scintilla_get_type();
+ }
+@@ -3200,6 +3204,7 @@ static void scintilla_init(ScintillaObje
  }
  
  /* legacy name for scintilla_object_new */
@@ -28,6 +42,14 @@ index 0871ca2..49dc278 100644
  GtkWidget* scintilla_new() {
  	GtkWidget *widget = GTK_WIDGET(g_object_new(scintilla_get_type(), NULL));
  	gtk_widget_set_direction(widget, GTK_TEXT_DIR_LTR);
+@@ -3207,6 +3212,7 @@ GtkWidget* scintilla_new() {
+ 	return widget;
+ }
+ 
++GEANY_API_SYMBOL
+ GtkWidget *scintilla_object_new() {
+ 	return scintilla_new();
+ }
 diff --git scintilla/gtk/scintilla-marshal.c scintilla/gtk/scintilla-marshal.c
 index be57b7c..cee3e73 100644
 --- scintilla/gtk/scintilla-marshal.c


Modified: scripts/plugin_test.c
123 lines changed, 0 insertions(+), 123 deletions(-)
===================================================================
@@ -1,123 +0,0 @@
-/*
- *      plugin_test.c
- *
- *      Copyright 2010-2011 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
- *      Copyright 2010-2011 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
- *
- *      This program is free software; you can redistribute it and/or modify
- *      it under the terms of the GNU General Public License as published by
- *      the Free Software Foundation; either version 2 of the License, or
- *      (at your option) any later version.
- *
- *      This program is distributed in the hope that it will be useful,
- *      but WITHOUT ANY WARRANTY; without even the implied warranty of
- *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *      GNU General Public License for more details.
- *
- *      You should have received a copy of the GNU General Public License
- *      along with this program; if not, write to the Free Software
- *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *      MA 02110-1301, USA.
- */
-
-
-/* This code tries to load the passed Geany plugin
- * (passed as path, e.g. pluginname.so) and looks up some symbols.
- * Example use case for this tool is to test whether a plugin is
- * loadable and defines all required symbols.
- *
- * This file is not built during the normal build process, instead
- * compile it on your with the following command in the root of the Geany source tree:
- *
- * cc -o plugin_test scripts/plugin_test.c `pkg-config --cflags --libs glib-2.0 gmodule-2.0`
- */
-
-#include <stdio.h>
-#include <glib.h>
-#include <gmodule.h>
-
-
-static gboolean tp_check_version(GModule *module)
-{
-	/* TODO implement me */
-	return TRUE;
-}
-
-
-static void tp_close_module(GModule *module)
-{
-	if (! g_module_close(module))
-		g_warning("%s: %s", g_module_name(module), g_module_error());
-}
-
-
-/* Emulate loading a plugin and looking up some symbols,
- * similar to what Geany would do on loading the plugin.
- */
-static gboolean test_plugin(const gchar *filename)
-{
-	GModule *module;
-	void (*plugin_set_info)(void*);
-	void (*init) (void *data);
-	void (*cleanup) (void);
-
-	g_return_val_if_fail(filename, FALSE);
-	g_return_val_if_fail(g_module_supported(), FALSE);
-
-	module = g_module_open(filename, G_MODULE_BIND_LOCAL);
-	if (! module)
-	{
-		g_warning("Can't load plugin: \"%s\": %s", filename, g_module_error());
-		return FALSE;
-	}
-
-	if (! tp_check_version(module))
-	{
-		tp_close_module(module);
-		return FALSE;
-	}
-
-	g_module_symbol(module, "plugin_set_info", (void *) &plugin_set_info);
-	if (plugin_set_info == NULL)
-	{
-		g_warning("No plugin_set_info() defined for \"%s\" - consider fixing the plugin!", filename);
-		tp_close_module(module);
-		return FALSE;
-	}
-
-	g_module_symbol(module, "plugin_init", (void *) &init);
-	if (init == NULL)
-	{
-		g_warning("Plugin '%s' has no plugin_init() function - consider fixing the plugin!", filename);
-		tp_close_module(module);
-		return FALSE;
-	}
-
-	g_module_symbol(module, "plugin_cleanup", (void *) &cleanup);
-	if (cleanup == NULL)
-	{
-		g_warning("Plugin '%s' has no plugin_cleanup() function - there may be memory leaks!", filename);
-	}
-
-	tp_close_module(module);
-
-	return TRUE;
-}
-
-
-gint main(gint argc, gchar **argv)
-{
-	gint i;
-	gint result = 0;
-
-	g_set_prgname("plugin_test");
-	/* we could perform better argument processing here as well as more error checking but
-	 * it's probably not worth at all */
-	for (i = 1; i < argc; i++)
-	{
-		if (! test_plugin(argv[i]))
-			result = 1;
-	}
-
-	return result;
-}


Modified: src/document.c
12 lines changed, 8 insertions(+), 4 deletions(-)
===================================================================
@@ -510,8 +510,12 @@ static gint document_get_new_idx(void)
 }
 
 
-static void queue_colourise(GeanyDocument *doc)
+static void queue_colourise(GeanyDocument *doc, gboolean full_colourise)
 {
+	/* make sure we don't override previously set full_colourise=TRUE by FALSE */
+	if (!doc->priv->colourise_needed || !doc->priv->full_colourise)
+		doc->priv->full_colourise = full_colourise;
+
 	/* Colourise the editor before it is next drawn */
 	doc->priv->colourise_needed = TRUE;
 
@@ -1394,7 +1398,7 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
 		/* add the text to the ScintillaObject */
 		sci_set_readonly(doc->editor->sci, FALSE);	/* to allow replacing text */
 		sci_set_text(doc->editor->sci, filedata.data);	/* NULL terminated data */
-		queue_colourise(doc);	/* Ensure the document gets colourised. */
+		queue_colourise(doc, TRUE);	/* Ensure the document gets colourised. */
 
 		/* detect & set line endings */
 		editor_mode = utils_get_line_endings(filedata.data, filedata.len);
@@ -2750,7 +2754,7 @@ void document_highlight_tags(GeanyDocument *doc)
 		keywords = g_string_free(keywords_str, FALSE);
 		sci_set_keywords(doc->editor->sci, keyword_idx, keywords);
 		g_free(keywords);
-		queue_colourise(doc); /* force re-highlighting the entire document */
+		queue_colourise(doc, FALSE); /* re-highlight the visible area */
 	}
 }
 
@@ -2811,7 +2815,7 @@ static void document_load_config(GeanyDocument *doc, GeanyFiletype *type,
 		highlighting_set_styles(doc->editor->sci, type);
 		editor_set_indentation_guides(doc->editor);
 		build_menu_update(doc);
-		queue_colourise(doc);
+		queue_colourise(doc, TRUE);
 		if (type->priv->symbol_list_sort_mode == SYMBOLS_SORT_USE_PREVIOUS)
 			doc->priv->symbol_list_sort_mode = interface_prefs.symbols_sort_mode;
 		else


Modified: src/documentprivate.h
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -90,6 +90,7 @@ typedef struct GeanyDocumentPrivate
 	/* Used so Undo/Redo works for encoding changes. */
 	FileEncoding	 saved_encoding;
 	gboolean		 colourise_needed;	/* use document.c:queue_colourise() instead */
+	gboolean		 full_colourise;
 	gint			 line_count;		/* Number of lines in the document. */
 	gint			 symbol_list_sort_mode;
 	/* indicates whether a file is on a remote filesystem, works only with GIO/GVfs */


Modified: src/editor.c
212 lines changed, 165 insertions(+), 47 deletions(-)
===================================================================
@@ -75,6 +75,7 @@ static GHashTable *snippet_hash = NULL;
 static GQueue *snippet_offsets = NULL;
 static gint snippet_cursor_insert_pos;
 static GtkAccelGroup *snippet_accel_group = NULL;
+static gboolean autocomplete_scope_shown = FALSE;
 
 static const gchar geany_cursor_marker[] = "__GEANY_CURSOR_MARKER__";
 
@@ -657,7 +658,9 @@ static gboolean match_last_chars(ScintillaObject *sci, gint pos, const gchar *st
 	gchar *buf;
 
 	g_return_val_if_fail(len < 100, FALSE);
-	g_return_val_if_fail((gint)len <= pos, FALSE);
+
+	if ((gint)len > pos)
+		return FALSE;
 
 	buf = g_alloca(len + 1);
 	sci_get_text_range(sci, pos - len, pos, buf);
@@ -697,51 +700,108 @@ static void request_reshowing_calltip(SCNotification *nt)
 }
 
 
-static void autocomplete_scope(GeanyEditor *editor)
+static gboolean autocomplete_scope(GeanyEditor *editor, const gchar *root, gsize rootlen)
 {
 	ScintillaObject *sci = editor->sci;
 	gint pos = sci_get_current_position(editor->sci);
 	gchar typed = sci_get_char_at(sci, pos - 1);
+	gchar brace_char;
 	gchar *name;
-	const GPtrArray *tags = NULL;
-	const TMTag *tag;
 	GeanyFiletype *ft = editor->document->file_type;
+	GPtrArray *tags;
+	gboolean function = FALSE;
+	gboolean member;
+	gboolean ret = FALSE;
+	const gchar *current_scope;
+	const gchar *context_sep = tm_tag_context_separator(ft->lang);
 
-	if (ft->id == GEANY_FILETYPES_C || ft->id == GEANY_FILETYPES_CPP)
+	if (autocomplete_scope_shown)
 	{
-		if (pos >= 2 && (match_last_chars(sci, pos, "->") || match_last_chars(sci, pos, "::")))
+		/* move at the operator position */
+		pos -= rootlen;
+
+		/* allow for a space between word and operator */
+		while (pos > 0 && isspace(sci_get_char_at(sci, pos - 1)))
 			pos--;
-		else if (ft->id == GEANY_FILETYPES_CPP && pos >= 3 && match_last_chars(sci, pos, "->*"))
-			pos-=2;
-		else if (typed != '.')
-			return;
+
+		if (pos > 0)
+			typed = sci_get_char_at(sci, pos - 1);
 	}
-	else if (typed != '.')
-		return;
+
+	/* make sure to keep in sync with similar checks below */
+	if (typed == '.')
+		pos -= 1;
+	else if (match_last_chars(sci, pos, context_sep))
+		pos -= strlen(context_sep);
+	else if ((ft->id == GEANY_FILETYPES_C || ft->id == GEANY_FILETYPES_CPP) &&
+			match_last_chars(sci, pos, "->"))
+		pos -= 2;
+	else if (ft->id == GEANY_FILETYPES_CPP && match_last_chars(sci, pos, "->*"))
+		pos -= 3;
+	else
+		return FALSE;
 
 	/* allow for a space between word and operator */
-	if (isspace(sci_get_char_at(sci, pos - 2)))
+	while (pos > 0 && isspace(sci_get_char_at(sci, pos - 1)))
 		pos--;
-	name = editor_get_word_at_pos(editor, pos - 1, NULL);
-	if (!name)
-		return;
 
-	tags = tm_workspace_find(name, tm_tag_max_t, NULL, FALSE, ft->lang);
-	g_free(name);
-	if (!tags || tags->len == 0)
-		return;
+	/* if function or array index, skip to matching brace */
+	brace_char = sci_get_char_at(sci, pos - 1);
+	if (pos > 0 && (brace_char == ')' || brace_char == ']'))
+	{
+		gint brace_pos = sci_find_matching_brace(sci, pos - 1);
 
-	tag = g_ptr_array_index(tags, 0);
-	name = tag->var_type;
-	if (name)
+		if (brace_pos != -1)
+		{
+			pos = brace_pos;
+			function = brace_char == ')';
+		}
+
+		/* allow for a space between opening brace and name */
+		while (pos > 0 && isspace(sci_get_char_at(sci, pos - 1)))
+			pos--;
+	}
+
+	name = editor_get_word_at_pos(editor, pos, NULL);
+	if (!name)
+		return FALSE;
+
+	/* check if invoked on member */
+	pos -= strlen(name);
+	while (pos > 0 && isspace(sci_get_char_at(sci, pos - 1)))
+		pos--;
+	/* make sure to keep in sync with similar checks above */
+	member = match_last_chars(sci, pos, ".") || match_last_chars(sci, pos, context_sep) ||
+			 match_last_chars(sci, pos, "->") || match_last_chars(sci, pos, "->*");
+
+	if (symbols_get_current_scope(editor->document, &current_scope) == -1)
+		current_scope = "";
+	tags = tm_workspace_find_scope_members(editor->document->tm_file, name, function,
+				member, current_scope);
+	if (tags)
 	{
-		TMSourceFile *obj = editor->document->tm_file;
+		GPtrArray *filtered = g_ptr_array_new();
+		TMTag *tag;
+		guint i;
+
+		foreach_ptr_array(tag, i, tags)
+		{
+			if (g_str_has_prefix(tag->name, root))
+				g_ptr_array_add(filtered, tag);
+		}
 
-		tags = tm_workspace_find_scope_members(obj ? obj->tags_array : NULL,
-			name, TRUE, FALSE);
-		if (tags)
-			show_tags_list(editor, tags, 0);
+		if (filtered->len > 0)
+		{
+			show_tags_list(editor, filtered, rootlen);
+			ret = TRUE;
+		}
+
+		g_ptr_array_free(tags, TRUE);
+		g_ptr_array_free(filtered, TRUE);
 	}
+
+	g_free(name);
+	return ret;
 }
 
 
@@ -1100,6 +1160,7 @@ static gboolean on_editor_notify(G_GNUC_UNUSED GObject *object, GeanyEditor *edi
 		case SCN_AUTOCCANCELLED:
 			/* now that autocomplete is finishing or was cancelled, reshow calltips
 			 * if they were showing */
+			autocomplete_scope_shown = FALSE;
 			request_reshowing_calltip(nt);
 			break;
 		case SCN_NEEDSHOWN:
@@ -1832,10 +1893,9 @@ static gboolean append_calltip(GString *str, const TMTag *tag, GeanyFiletypeID f
 
 static gchar *find_calltip(const gchar *word, GeanyFiletype *ft)
 {
-	const GPtrArray *tags;
+	GPtrArray *tags;
 	const TMTagType arg_types = tm_tag_function_t | tm_tag_prototype_t |
 		tm_tag_method_t | tm_tag_macro_with_arg_t;
-	TMTagAttrType *attrs = NULL;
 	TMTag *tag;
 	GString *str = NULL;
 	guint i;
@@ -1843,20 +1903,26 @@ static gchar *find_calltip(const gchar *word, GeanyFiletype *ft)
 	g_return_val_if_fail(ft && word && *word, NULL);
 
 	/* use all types in case language uses wrong tag type e.g. python "members" instead of "methods" */
-	tags = tm_workspace_find(word, tm_tag_max_t, attrs, FALSE, ft->lang);
+	tags = tm_workspace_find(word, NULL, tm_tag_max_t, NULL, ft->lang);
 	if (tags->len == 0)
+	{
+		g_ptr_array_free(tags, TRUE);
 		return NULL;
+	}
 
 	tag = TM_TAG(tags->pdata[0]);
 
 	if (ft->id == GEANY_FILETYPES_D &&
 		(tag->type == tm_tag_class_t || tag->type == tm_tag_struct_t))
 	{
+		g_ptr_array_free(tags, TRUE);
 		/* user typed e.g. 'new Classname(' so lookup D constructor Classname::this() */
-		tags = tm_workspace_find_scoped("this", tag->name,
-			arg_types, attrs, FALSE, ft->lang, TRUE);
+		tags = tm_workspace_find("this", tag->name, arg_types, NULL, ft->lang);
 		if (tags->len == 0)
+		{
+			g_ptr_array_free(tags, TRUE);
 			return NULL;
+		}
 	}
 
 	/* remove tags with no argument list */
@@ -1869,7 +1935,10 @@ static gchar *find_calltip(const gchar *word, GeanyFiletype *ft)
 	}
 	tm_tags_prune((GPtrArray *) tags);
 	if (tags->len == 0)
+	{
+		g_ptr_array_free(tags, TRUE);
 		return NULL;
+	}
 	else
 	{	/* remove duplicate calltips */
 		TMTagAttrType sort_attr[] = {tm_tag_attr_name_t, tm_tag_attr_scope_t,
@@ -1906,6 +1975,9 @@ static gchar *find_calltip(const gchar *word, GeanyFiletype *ft)
 			break;
 		}
 	}
+
+	g_ptr_array_free(tags, TRUE);
+
 	if (str)
 	{
 		gchar *result = str->str;
@@ -1951,6 +2023,20 @@ gboolean editor_show_calltip(GeanyEditor *editor, gint pos)
 	if (! highlighting_is_code_style(lexer, style))
 		return FALSE;
 
+	while (pos > 0 && isspace(sci_get_char_at(sci, pos - 1)))
+		pos--;
+
+	/* skip possible generic/template specification, like foo<int>() */
+	if (sci_get_char_at(sci, pos - 1) == '>')
+	{
+		pos = sci_find_matching_brace(sci, pos - 1);
+		if (pos == -1)
+			return FALSE;
+
+		while (pos > 0 && isspace(sci_get_char_at(sci, pos - 1)))
+			pos--;
+	}
+
 	word[0] = '\0';
 	editor_find_current_word(editor, pos - 1, word, sizeof word, NULL);
 	if (word[0] == '\0')
@@ -2027,21 +2113,21 @@ autocomplete_html(ScintillaObject *sci, const gchar *root, gsize rootlen)
 static gboolean
 autocomplete_tags(GeanyEditor *editor, const gchar *root, gsize rootlen)
 {
-	TMTagAttrType attrs[] = { tm_tag_attr_name_t, 0 };
-	const GPtrArray *tags;
+	GPtrArray *tags;
 	GeanyDocument *doc;
+	gboolean found;
 
 	g_return_val_if_fail(editor, FALSE);
 
 	doc = editor->document;
 
-	tags = tm_workspace_find(root, tm_tag_max_t, attrs, TRUE, doc->file_type->lang);
-	if (tags)
-	{
+	tags = tm_workspace_find_prefix(root, doc->file_type->lang, editor_prefs.autocompletion_max_entries);
+	found = tags->len > 0;
+	if (found)
 		show_tags_list(editor, tags, rootlen);
-		return tags->len > 0;
-	}
-	return FALSE;
+	g_ptr_array_free(tags, TRUE);
+
+	return found;
 }
 
 
@@ -2201,7 +2287,6 @@ gboolean editor_start_auto_complete(GeanyEditor *editor, gint pos, gboolean forc
 	if (!force && !highlighting_is_code_style(lexer, style))
 		return FALSE;
 
-	autocomplete_scope(editor);
 	ret = autocomplete_check_html(editor, style, pos);
 
 	if (ft->id == GEANY_FILETYPES_LATEX)
@@ -2215,6 +2300,23 @@ gboolean editor_start_auto_complete(GeanyEditor *editor, gint pos, gboolean forc
 	root = cword;
 	rootlen = strlen(root);
 
+	if (ret || force)
+	{
+		if (autocomplete_scope_shown)
+		{
+			autocomplete_scope_shown = FALSE;
+			if (!ret)
+				sci_send_command(sci, SCI_AUTOCCANCEL);
+		}
+	}
+	else
+	{
+		ret = autocomplete_scope(editor, root, rootlen);
+		if (!ret && autocomplete_scope_shown)
+			sci_send_command(sci, SCI_AUTOCCANCEL);
+		autocomplete_scope_shown = ret;
+	}
+
 	if (!ret && rootlen > 0)
 	{
 		if (ft->id == GEANY_FILETYPES_PHP && style == SCE_HPHP_DEFAULT &&
@@ -4687,12 +4789,28 @@ static gboolean editor_check_colourise(GeanyEditor *editor)
 		return FALSE;
 
 	doc->priv->colourise_needed = FALSE;
-	sci_colourise(editor->sci, 0, -1);
 
-	/* now that the current document is colourised, fold points are now accurate,
-	 * so force an update of the current function/tag. */
-	symbols_get_current_function(NULL, NULL);
-	ui_update_statusbar(NULL, -1);
+	if (doc->priv->full_colourise)
+	{
+		sci_colourise(editor->sci, 0, -1);
+
+		/* now that the current document is colourised, fold points are now accurate,
+		 * so force an update of the current function/tag. */
+		symbols_get_current_function(NULL, NULL);
+		ui_update_statusbar(NULL, -1);
+	}
+	else
+	{
+		gint start_line, end_line, start, end;
+
+		start_line = SSM(doc->editor->sci, SCI_GETFIRSTVISIBLELINE, 0, 0);
+		end_line = start_line + SSM(editor->sci, SCI_LINESONSCREEN, 0, 0);
+		start_line = SSM(editor->sci, SCI_DOCLINEFROMVISIBLE, start_line, 0);
+		end_line = SSM(editor->sci, SCI_DOCLINEFROMVISIBLE, end_line, 0);
+		start = sci_get_position_from_line(editor->sci, start_line);
+		end = sci_get_line_end_position(editor->sci, end_line);
+		sci_colourise(editor->sci, start, end);
+	}
 
 	return TRUE;
 }


Modified: src/filetypes.c
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -951,7 +951,7 @@ static void load_settings(guint ft_id, GKeyFile *config, GKeyFile *configh)
 	{
 		ft->lang = tm_source_file_get_named_lang(result);
 		if (ft->lang < 0)
-			geany_debug("Cannot find tag parser '%s' for custom filetype '%s'.", result, ft->name);
+			geany_debug("Cannot find tags parser '%s' for custom filetype '%s'.", result, ft->name);
 		g_free(result);
 	}
 


Modified: src/keybindings.c
40 lines changed, 38 insertions(+), 2 deletions(-)
===================================================================
@@ -476,6 +476,18 @@ static void init_default_kb(void)
 		GDK_2, GEANY_PRIMARY_MOD_MASK, "edit_sendtocmd2", _("Send to Custom Command 2"), NULL);
 	add_kb(group, GEANY_KEYS_FORMAT_SENDTOCMD3, NULL,
 		GDK_3, GEANY_PRIMARY_MOD_MASK, "edit_sendtocmd3", _("Send to Custom Command 3"), NULL);
+	add_kb(group, GEANY_KEYS_FORMAT_SENDTOCMD4, NULL,
+		0, 0, "edit_sendtocmd4", _("Send to Custom Command 4"), NULL);
+	add_kb(group, GEANY_KEYS_FORMAT_SENDTOCMD5, NULL,
+		0, 0, "edit_sendtocmd5", _("Send to Custom Command 5"), NULL);
+	add_kb(group, GEANY_KEYS_FORMAT_SENDTOCMD6, NULL,
+		0, 0, "edit_sendtocmd6", _("Send to Custom Command 6"), NULL);
+	add_kb(group, GEANY_KEYS_FORMAT_SENDTOCMD7, NULL,
+		0, 0, "edit_sendtocmd7", _("Send to Custom Command 7"), NULL);
+	add_kb(group, GEANY_KEYS_FORMAT_SENDTOCMD8, NULL,
+		0, 0, "edit_sendtocmd8", _("Send to Custom Command 8"), NULL);
+	add_kb(group, GEANY_KEYS_FORMAT_SENDTOCMD9, NULL,
+		0, 0, "edit_sendtocmd9", _("Send to Custom Command 9"), NULL);
 	/* may fit better in editor group */
 	add_kb(group, GEANY_KEYS_FORMAT_SENDTOVTE, NULL,
 		0, 0, "edit_sendtovte", _("_Send Selection to Terminal"), "send_selection_to_vte1");
@@ -559,10 +571,10 @@ static void init_default_kb(void)
 		_("Go to Pre_vious Marker"), "go_to_previous_marker1");
 	add_kb(group, GEANY_KEYS_GOTO_TAGDEFINITION, NULL,
 		GDK_t, GEANY_PRIMARY_MOD_MASK, "popup_gototagdefinition",
-		_("Go to Tag Definition"), "goto_tag_definition1");
+		_("Go to Symbol Definition"), "goto_tag_definition1");
 	add_kb(group, GEANY_KEYS_GOTO_TAGDECLARATION, NULL,
 		GDK_t, GEANY_PRIMARY_MOD_MASK | GDK_SHIFT_MASK, "popup_gototagdeclaration",
-		_("Go to Tag Declaration"), "goto_tag_declaration1");
+		_("Go to Symbol Declaration"), "goto_tag_declaration1");
 	add_kb(group, GEANY_KEYS_GOTO_LINESTART, NULL,
 		GDK_Home, 0, "edit_gotolinestart", _("Go to Start of Line"), NULL);
 	add_kb(group, GEANY_KEYS_GOTO_LINEEND, NULL,
@@ -2431,6 +2443,30 @@ static gboolean cb_func_format_action(guint key_id)
 			if (ui_prefs.custom_commands && g_strv_length(ui_prefs.custom_commands) > 2)
 				tools_execute_custom_command(doc, ui_prefs.custom_commands[2]);
 			break;
+		case GEANY_KEYS_FORMAT_SENDTOCMD4:
+			if (ui_prefs.custom_commands && g_strv_length(ui_prefs.custom_commands) > 3)
+				tools_execute_custom_command(doc, ui_prefs.custom_commands[3]);
+			break;
+		case GEANY_KEYS_FORMAT_SENDTOCMD5:
+			if (ui_prefs.custom_commands && g_strv_length(ui_prefs.custom_commands) > 4)
+				tools_execute_custom_command(doc, ui_prefs.custom_commands[4]);
+			break;
+		case GEANY_KEYS_FORMAT_SENDTOCMD6:
+			if (ui_prefs.custom_commands && g_strv_length(ui_prefs.custom_commands) > 5)
+				tools_execute_custom_command(doc, ui_prefs.custom_commands[5]);
+			break;
+		case GEANY_KEYS_FORMAT_SENDTOCMD7:
+			if (ui_prefs.custom_commands && g_strv_length(ui_prefs.custom_commands) > 6)
+				tools_execute_custom_command(doc, ui_prefs.custom_commands[6]);
+			break;
+		case GEANY_KEYS_FORMAT_SENDTOCMD8:
+			if (ui_prefs.custom_commands && g_strv_length(ui_prefs.custom_commands) > 7)
+				tools_execute_custom_command(doc, ui_prefs.custom_commands[7]);
+			break;
+		case GEANY_KEYS_FORMAT_SENDTOCMD9:
+			if (ui_prefs.custom_commands && g_strv_length(ui_prefs.custom_commands) > 8)
+				tools_execute_custom_command(doc, ui_prefs.custom_commands[8]);
+			break;
 		case GEANY_KEYS_FORMAT_SENDTOVTE:
 			on_send_selection_to_vte1_activate(NULL, NULL);
 			break;


Modified: src/keybindings.h
6 lines changed, 6 insertions(+), 0 deletions(-)
===================================================================
@@ -267,6 +267,12 @@ enum GeanyKeyBindingID
 	GEANY_KEYS_DOCUMENT_CLONE,					/**< Keybinding. */
 	GEANY_KEYS_FILE_QUIT,						/**< Keybinding. */
 	GEANY_KEYS_FILE_PROPERTIES,					/**< Keybinding. */
+	GEANY_KEYS_FORMAT_SENDTOCMD4,				/**< Keybinding. */
+	GEANY_KEYS_FORMAT_SENDTOCMD5,				/**< Keybinding. */
+	GEANY_KEYS_FORMAT_SENDTOCMD6,				/**< Keybinding. */
+	GEANY_KEYS_FORMAT_SENDTOCMD7,				/**< Keybinding. */
+	GEANY_KEYS_FORMAT_SENDTOCMD8,				/**< Keybinding. */
+	GEANY_KEYS_FORMAT_SENDTOCMD9,				/**< Keybinding. */
 	GEANY_KEYS_COUNT	/* must not be used by plugins */
 };
 


Modified: src/libmain.c
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -119,7 +119,7 @@ static GOptionEntry entries[] =
 	{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &alternate_config, N_("Use an alternate configuration directory"), NULL },
 	{ "ft-names", 0, 0, G_OPTION_ARG_NONE, &ft_names, N_("Print internal filetype names"), NULL },
 	{ "generate-tags", 'g', 0, G_OPTION_ARG_NONE, &generate_tags, N_("Generate global tags file (see documentation)"), NULL },
-	{ "no-preprocessing", 'P', 0, G_OPTION_ARG_NONE, &no_preprocessing, N_("Don't preprocess C/C++ files when generating tags"), NULL },
+	{ "no-preprocessing", 'P', 0, G_OPTION_ARG_NONE, &no_preprocessing, N_("Don't preprocess C/C++ files when generating tags file"), NULL },
 #ifdef HAVE_SOCKET
 	{ "new-instance", 'i', 0, G_OPTION_ARG_NONE, &cl_options.new_instance, N_("Don't open files in a running instance, force opening a new instance"), NULL },
 	{ "socket-file", 0, 0, G_OPTION_ARG_FILENAME, &cl_options.socket_filename, N_("Use this socket filename for communication with a running Geany instance"), NULL },


Modified: src/sidebar.c
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -175,7 +175,7 @@ static void create_default_tag_tree(void)
 		gtk_scrolled_window_get_hadjustment(scrolled_window),
 		gtk_scrolled_window_get_vadjustment(scrolled_window));
 	gtk_viewport_set_shadow_type(GTK_VIEWPORT(tv.default_tag_tree), GTK_SHADOW_NONE);
-	label = gtk_label_new(_("No tags found"));
+	label = gtk_label_new(_("No symbols found"));
 	gtk_misc_set_alignment(GTK_MISC(label), 0.1f, 0.01f);
 	gtk_container_add(GTK_CONTAINER(tv.default_tag_tree), label);
 	gtk_widget_show_all(tv.default_tag_tree);


Modified: src/spawn.c
6 lines changed, 4 insertions(+), 2 deletions(-)
===================================================================
@@ -1202,8 +1202,10 @@ gboolean spawn_sync(const gchar *working_directory, const gchar *command_line, g
 	gchar **envp, SpawnWriteData *stdin_data, GString *stdout_data, GString *stderr_data,
 	gint *exit_status, GError **error)
 {
-	g_string_truncate(stdout_data, 0);
-	g_string_truncate(stderr_data, 0);
+	if (stdout_data)
+		g_string_truncate(stdout_data, 0);
+	if (stderr_data)
+		g_string_truncate(stderr_data, 0);
 
 	return spawn_with_callbacks(working_directory, command_line, argv, envp, SPAWN_SYNC |
 		SPAWN_UNBUFFERED, stdin_data ? (GIOFunc) spawn_write_data : NULL, stdin_data,


Modified: src/stash.c
46 lines changed, 33 insertions(+), 13 deletions(-)
===================================================================
@@ -123,6 +123,7 @@ typedef struct StashPref StashPref;
 
 struct StashGroup
 {
+	guint refcount;				/* ref count for GBoxed implementation */
 	const gchar *name;			/* group name to use in the keyfile */
 	GPtrArray *entries;			/* array of (StashPref*) */
 	gboolean various;		/* mark group for display/edit in stash treeview */
@@ -347,17 +348,27 @@ gint stash_group_save_to_file(StashGroup *group, const gchar *filename,
 }
 
 
+static void free_stash_pref(StashPref *pref)
+{
+	if (pref->widget_type == GTK_TYPE_RADIO_BUTTON)
+		g_free(pref->extra.radio_buttons);
+
+	g_slice_free(StashPref, pref);
+}
+
+
 /** Creates a new group.
  * @param name Name used for @c GKeyFile group.
  * @return Group. */
 GEANY_API_SYMBOL
 StashGroup *stash_group_new(const gchar *name)
 {
-	StashGroup *group = g_new0(StashGroup, 1);
+	StashGroup *group = g_slice_new0(StashGroup);
 
 	group->name = name;
-	group->entries = g_ptr_array_new();
+	group->entries = g_ptr_array_new_with_free_func((GDestroyNotify) free_stash_pref);
 	group->use_defaults = TRUE;
+	group->refcount = 1;
 	return group;
 }
 
@@ -386,27 +397,36 @@ void stash_group_free_settings(StashGroup *group)
 }
 
 
+static StashGroup *stash_group_dup(StashGroup *src)
+{
+	g_atomic_int_inc(&src->refcount);
+
+	return src;
+}
+
+
 /** Frees a group.
  * @param group . */
 GEANY_API_SYMBOL
 void stash_group_free(StashGroup *group)
 {
-	StashPref *entry;
-	guint i;
-
-	foreach_ptr_array(entry, i, group->entries)
+	if (g_atomic_int_dec_and_test(&group->refcount))
 	{
-		if (entry->widget_type == GTK_TYPE_RADIO_BUTTON)
-		{
-			g_free(entry->extra.radio_buttons);
-		}
-		g_slice_free(StashPref, entry);
+		g_ptr_array_free(group->entries, TRUE);
+		g_slice_free(StashGroup, group);
 	}
-	g_ptr_array_free(group->entries, TRUE);
-	g_free(group);
 }
 
 
+/** Gets the GBoxed-derived GType for StashGroup
+ *
+ * @return StashGroup type . */
+GEANY_API_SYMBOL
+GType stash_group_get_type(void);
+
+G_DEFINE_BOXED_TYPE(StashGroup, stash_group, stash_group_dup, stash_group_free);
+
+
 /* Used for selecting groups passed to stash_tree_setup().
  * @c FALSE by default. */
 void stash_group_set_various(StashGroup *group, gboolean various)


Modified: src/stash.h
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -33,6 +33,7 @@ typedef struct StashGroup StashGroup;
  * stash_group_display() and stash_group_update(). */
 typedef gconstpointer StashWidgetID;
 
+GType stash_group_get_type(void);
 
 StashGroup *stash_group_new(const gchar *name);
 


Modified: src/symbols.c
40 lines changed, 7 insertions(+), 33 deletions(-)
===================================================================
@@ -190,7 +190,7 @@ static gboolean symbols_load_global_tags(const gchar *tags_file, GeanyFiletype *
 	result = tm_workspace_load_global_tags(tags_file, ft->lang);
 	if (result)
 	{
-		geany_debug("Loaded %s (%s), %u tag(s).", tags_file, ft->name,
+		geany_debug("Loaded %s (%s), %u symbol(s).", tags_file, ft->name,
 			(guint) (get_tag_count() - old_tag_count));
 	}
 	return result;
@@ -281,7 +281,7 @@ GString *symbols_find_typenames_as_string(gint lang, gboolean global)
 	gint tag_lang;
 
 	if (global)
-		typedefs = tm_tags_extract(app->tm_workspace->global_tags, TM_GLOBAL_TYPE_MASK);
+		typedefs = app->tm_workspace->global_typename_array;
 	else
 		typedefs = app->tm_workspace->typename_array;
 
@@ -305,8 +305,6 @@ GString *symbols_find_typenames_as_string(gint lang, gboolean global)
 			}
 		}
 	}
-	if (typedefs && global)
-		g_ptr_array_free(typedefs, TRUE);
 	return s;
 }
 
@@ -324,31 +322,7 @@ GString *symbols_find_typenames_as_string(gint lang, gboolean global)
 GEANY_API_SYMBOL
 const gchar *symbols_get_context_separator(gint ft_id)
 {
-	switch (ft_id)
-	{
-		case GEANY_FILETYPES_C:	/* for C++ .h headers or C structs */
-		case GEANY_FILETYPES_CPP:
-		case GEANY_FILETYPES_GLSL:	/* for structs */
-		/*case GEANY_FILETYPES_RUBY:*/ /* not sure what to use atm*/
-		case GEANY_FILETYPES_PHP:
-		case GEANY_FILETYPES_POWERSHELL:
-		case GEANY_FILETYPES_RUST:
-		case GEANY_FILETYPES_ZEPHIR:
-			return "::";
-
-		/* avoid confusion with other possible separators in group/section name */
-		case GEANY_FILETYPES_CONF:
-		case GEANY_FILETYPES_REST:
-			return ":::";
-
-		/* no context separator */
-		case GEANY_FILETYPES_ASCIIDOC:
-		case GEANY_FILETYPES_TXT2TAGS:
-			return "\x03";
-
-		default:
-			return ".";
-	}
+	return tm_tag_context_separator(filetypes[ft_id]->lang);
 }
 
 
@@ -1779,14 +1753,14 @@ int symbols_generate_global_tags(int argc, char **argv, gboolean want_preprocess
 		symbols_finalize(); /* free c_tags_ignore data */
 		if (! status)
 		{
-			g_printerr(_("Failed to create tags file, perhaps because no tags "
+			g_printerr(_("Failed to create tags file, perhaps because no symbols "
 				"were found.\n"));
 			return 1;
 		}
 	}
 	else
 	{
-		g_printerr(_("Usage: %s -g <Tag File> <File list>\n\n"), argv[0]);
+		g_printerr(_("Usage: %s -g <Tags File> <File list>\n\n"), argv[0]);
 		g_printerr(_("Example:\n"
 			"CFLAGS=`pkg-config gtk+-2.0 --cflags` %s -g gtk2.c.tags"
 			" /usr/include/gtk-2.0/gtk/gtk.h\n"), argv[0]);
@@ -1801,14 +1775,14 @@ void symbols_show_load_tags_dialog(void)
 	GtkWidget *dialog;
 	GtkFileFilter *filter;
 
-	dialog = gtk_file_chooser_dialog_new(_("Load Tags"), GTK_WINDOW(main_widgets.window),
+	dialog = gtk_file_chooser_dialog_new(_("Load Tags File"), GTK_WINDOW(main_widgets.window),
 		GTK_FILE_CHOOSER_ACTION_OPEN,
 		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 		GTK_STOCK_OPEN, GTK_RESPONSE_OK,
 		NULL);
 	gtk_widget_set_name(dialog, "GeanyDialog");
 	filter = gtk_file_filter_new();
-	gtk_file_filter_set_name(filter, _("Geany tag files (*.*.tags)"));
+	gtk_file_filter_set_name(filter, _("Geany tags file (*.*.tags)"));
 	gtk_file_filter_add_pattern(filter, "*.*.tags");
 	gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
 


Modified: src/tools.c
6 lines changed, 6 insertions(+), 0 deletions(-)
===================================================================
@@ -554,6 +554,12 @@ static void cc_insert_custom_command_items(GtkMenu *me, const gchar *label, cons
 		case 0: key_idx = GEANY_KEYS_FORMAT_SENDTOCMD1; break;
 		case 1: key_idx = GEANY_KEYS_FORMAT_SENDTOCMD2; break;
 		case 2: key_idx = GEANY_KEYS_FORMAT_SENDTOCMD3; break;
+		case 3: key_idx = GEANY_KEYS_FORMAT_SENDTOCMD4; break;
+		case 4: key_idx = GEANY_KEYS_FORMAT_SENDTOCMD5; break;
+		case 5: key_idx = GEANY_KEYS_FORMAT_SENDTOCMD6; break;
+		case 6: key_idx = GEANY_KEYS_FORMAT_SENDTOCMD7; break;
+		case 7: key_idx = GEANY_KEYS_FORMAT_SENDTOCMD8; break;
+		case 8: key_idx = GEANY_KEYS_FORMAT_SENDTOCMD9; break;
 	}
 
 	item = gtk_menu_item_new_with_label(label);


Modified: tagmanager/ctags/c.c
72 lines changed, 62 insertions(+), 10 deletions(-)
===================================================================
@@ -518,7 +518,8 @@ static const keywordDesc KeywordTable [] = {
 */
 static void createTags (const unsigned int nestLevel, statementInfo *const parent);
 static void copyToken (tokenInfo *const dest, const tokenInfo *const src);
-static const char *getVarType (const statementInfo *const st);
+static const char *getVarType (const statementInfo *const st,
+							   const tokenInfo *const token);
 
 /*
 *   FUNCTION DEFINITIONS
@@ -1186,6 +1187,7 @@ static const char* accessField (const statementInfo *const st)
 }
 
 static void addOtherFields (tagEntryInfo* const tag, const tagType type,
+							const tokenInfo *const nameToken,
 							const statementInfo *const st, vString *const scope)
 {
 	/*  For selected tag types, append an extension flag designating the
@@ -1254,40 +1256,90 @@ static void addOtherFields (tagEntryInfo* const tag, const tagType type,
 		if (((TOKEN_NAME == st->firstToken->type) || isDataTypeKeyword(st->firstToken))
 			&& (0 != strcmp(vStringValue(st->firstToken->name), tag->name)))
 		{
-			tag->extensionFields.varType = getVarType(st);
+			tag->extensionFields.varType = getVarType(st, nameToken);
 		}
 	}
 }
 
-static const char *getVarType (const statementInfo *const st)
+static const char *getVarType (const statementInfo *const st,
+							   const tokenInfo *const nameToken)
 {
 	static vString *vt = NULL;
 	unsigned int i;
+	unsigned int end = st->tokenIndex;
+	boolean seenType = FALSE;
 
-	if (! st->gotArgs)
-		return vStringValue(st->firstToken->name);	/* ignore non-functions */
+	switch (st->declaration) {
+		case DECL_BASE:
+		case DECL_FUNCTION:
+		case DECL_FUNCTION_TEMPLATE:
+			break;
+		default:
+			return vStringValue(st->firstToken->name);
+	}
 
 	if (vt == NULL)
 		vt = vStringNew();
 	else
 		vStringClear(vt);
 
+	/* find the end of the type signature in the token list */
 	for (i = 0; i < st->tokenIndex; i++)
 	{
+		const tokenInfo *const t = st->token[i];
+
+		/* stop if we find the token used to generate the tag name, or
+		 * a name token in the middle yet not preceded by a scope separator */
+		if ((t == nameToken ||
+		     (t->type == nameToken->type &&
+		      t->keyword == nameToken->keyword &&
+		      t->lineNumber == nameToken->lineNumber &&
+		      strcmp(vStringValue(t->name), vStringValue(nameToken->name)) == 0)) ||
+		    (t->type == TOKEN_NAME && seenType &&
+		     (i > 0 && st->token[i - 1]->type != TOKEN_DOUBLE_COLON)))
+		{
+			break;
+		}
+		if (t->type != TOKEN_DOUBLE_COLON)
+			end = i + 1;
+		if (t->type == TOKEN_NAME)
+			seenType = TRUE;
+		else if (t->type == TOKEN_KEYWORD && isDataTypeKeyword(t))
+			seenType = TRUE;
+	}
+
+	/* ugly historic workaround when we can't figure out the type */
+	if (end < 2 && ! st->gotArgs)
+		return vStringValue(st->firstToken->name);
+
+	for (i = 0; i < end; i++)
+	{
 		tokenInfo *t = st->token[i];
 
 		switch (t->type)
 		{
 			case TOKEN_NAME:	/* user typename */
-				if (strcmp(vStringValue(t->name), vStringValue(st->firstToken->name)) != 0)
-					continue;
 				break;
 			case TOKEN_KEYWORD:
-				if (t->keyword != KEYWORD_EXTERN && t->keyword != KEYWORD_STATIC)	/* uninteresting keywords */
+				if ((t->keyword != KEYWORD_EXTERN && t->keyword != KEYWORD_STATIC) &&	/* uninteresting keywords */
+				    (st->gotArgs ||
+				     /* ignore uninteresting keywords for non-functions */
+				     (t->keyword != KEYWORD_PUBLIC &&
+				      t->keyword != KEYWORD_PRIVATE &&
+				      t->keyword != KEYWORD_PROTECTED &&
+				      t->keyword != KEYWORD_FINAL &&
+				      t->keyword != KEYWORD_TYPEDEF &&
+				      /* hack for D static conditions */
+				      t->keyword != KEYWORD_IF)))
+				{
 					break;
+				}
 				continue;
 			case TOKEN_STAR: vStringCatS(vt, " *"); continue;
 			case TOKEN_ARRAY: vStringCatS(vt, "[]"); continue;
+			case TOKEN_DOUBLE_COLON:
+				vStringCatS(vt, "::");
+				continue;
 			default: continue;
 		}
 		if (vStringLength(vt) > 0)
@@ -1426,7 +1478,7 @@ static void makeTag (const tokenInfo *const token,
 		e.type = type;
 
 		findScopeHierarchy (scope, st);
-		addOtherFields (&e, type, st, scope);
+		addOtherFields (&e, type, token, st, scope);
 
 #ifdef DEBUG_C
 		printTagEntry(&e);
@@ -3120,7 +3172,7 @@ static boolean findCTags (const unsigned int passCount)
 	contextual_fake_count = 0;
 
 	Assert (passCount < 3);
-	cppInit ((boolean) (passCount > 1), isLanguage (Lang_csharp));
+	cppInit ((boolean) (passCount > 1), isLanguage (Lang_csharp), isLanguage (Lang_cpp));
 
 	exception = (exception_t) setjmp (Exception);
 	retry = FALSE;


Modified: tagmanager/ctags/get.c
93 lines changed, 92 insertions(+), 1 deletions(-)
===================================================================
@@ -62,6 +62,7 @@ typedef struct sCppState {
 	int		ungetch, ungetch2;   /* ungotten characters, if any */
 	boolean resolveRequired;     /* must resolve if/else/elif/endif branch */
 	boolean hasAtLiteralStrings; /* supports @"c:\" strings */
+	boolean hasCxxRawLiteralStrings; /* supports R"xxx(...)xxx" strings */
 	struct sDirective {
 		enum eState state;       /* current directive being processed */
 		boolean	accept;          /* is a directive syntactically permitted? */
@@ -83,6 +84,7 @@ static cppState Cpp = {
 	'\0', '\0',  /* ungetch characters */
 	FALSE,       /* resolveRequired */
 	FALSE,       /* hasAtLiteralStrings */
+	FALSE,       /* hasCxxRawLiteralStrings */
 	{
 		DRCTV_NONE,  /* state */
 		FALSE,       /* accept */
@@ -106,7 +108,8 @@ extern unsigned int getDirectiveNestLevel (void)
 	return Cpp.directive.nestLevel;
 }
 
-extern void cppInit (const boolean state, const boolean hasAtLiteralStrings)
+extern void cppInit (const boolean state, const boolean hasAtLiteralStrings,
+                     const boolean hasCxxRawLiteralStrings)
 {
 	BraceFormat = state;
 
@@ -114,6 +117,7 @@ extern void cppInit (const boolean state, const boolean hasAtLiteralStrings)
 	Cpp.ungetch2        = '\0';
 	Cpp.resolveRequired = FALSE;
 	Cpp.hasAtLiteralStrings = hasAtLiteralStrings;
+	Cpp.hasCxxRawLiteralStrings = hasCxxRawLiteralStrings;
 
 	Cpp.directive.state     = DRCTV_NONE;
 	Cpp.directive.accept    = TRUE;
@@ -533,6 +537,55 @@ static int skipToEndOfString (boolean ignoreBackslash)
 	return STRING_SYMBOL;  /* symbolic representation of string */
 }
 
+static int isCxxRawLiteralDelimiterChar (int c)
+{
+	return (c != ' ' && c != '\f' && c != '\n' && c != '\r' && c != '\t' && c != '\v' &&
+	        c != '(' && c != ')' && c != '\\');
+}
+
+static int skipToEndOfCxxRawLiteralString (void)
+{
+	int c = fileGetc ();
+
+	if (c != '(' && ! isCxxRawLiteralDelimiterChar (c))
+	{
+		fileUngetc (c);
+		c = skipToEndOfString (FALSE);
+	}
+	else
+	{
+		char delim[16];
+		unsigned int delimLen = 0;
+		boolean collectDelim = TRUE;
+
+		do
+		{
+			if (collectDelim)
+			{
+				if (isCxxRawLiteralDelimiterChar (c) &&
+				    delimLen < (sizeof delim / sizeof *delim))
+					delim[delimLen++] = c;
+				else
+					collectDelim = FALSE;
+			}
+			else if (c == ')')
+			{
+				unsigned int i = 0;
+
+				while ((c = fileGetc ()) != EOF && i < delimLen && delim[i] == c)
+					i++;
+				if (i == delimLen && c == DOUBLE_QUOTE)
+					break;
+				else
+					fileUngetc (c);
+			}
+		}
+		while ((c = fileGetc ()) != EOF);
+		c = STRING_SYMBOL;
+	}
+	return c;
+}
+
 /*  Skips to the end of the three (possibly four) 'c' sequence, returning a
  *  special character to symbolically represent a generic character.
  *  Also detects Vera numbers that include a base specifier (ie. 'b1010).
@@ -729,6 +782,44 @@ extern int cppGetc (void)
 					else
 						fileUngetc (next);
 				}
+				else if (c == 'R' && Cpp.hasCxxRawLiteralStrings)
+				{
+					/* OMG!11 HACK!!11  Get the previous character.
+					 *
+					 * We need to know whether the previous character was an identifier or not,
+					 * because "R" has to be on its own, not part of an identifier.  This allows
+					 * for constructs like:
+					 *
+					 * 	#define FOUR "4"
+					 * 	const char *p = FOUR"5";
+					 *
+					 * which is not a raw literal, but a preprocessor concatenation.
+					 *
+					 * FIXME: handle
+					 *
+					 * 	const char *p = R\
+					 * 	"xxx(raw)xxx";
+					 *
+					 * which is perfectly valid (yet probably very unlikely). */
+					int prev = fileGetNthPrevC (1, '\0');
+					int prev2 = fileGetNthPrevC (2, '\0');
+					int prev3 = fileGetNthPrevC (3, '\0');
+
+					if (! isident (prev) ||
+					    (! isident (prev2) && (prev == 'L' || prev == 'u' || prev == 'U')) ||
+					    (! isident (prev3) && (prev2 == 'u' && prev == '8')))
+					{
+						int next = fileGetc ();
+						if (next != DOUBLE_QUOTE)
+							fileUngetc (next);
+						else
+						{
+							Cpp.directive.accept = FALSE;
+							c = skipToEndOfCxxRawLiteralString ();
+							break;
+						}
+					}
+				}
 			enter:
 				Cpp.directive.accept = FALSE;
 				if (directive)


Modified: tagmanager/ctags/get.h
3 lines changed, 2 insertions(+), 1 deletions(-)
===================================================================
@@ -36,7 +36,8 @@
 */
 extern boolean isBraceFormat (void);
 extern unsigned int getDirectiveNestLevel (void);
-extern void cppInit (const boolean state, const boolean hasAtLiteralStrings);
+extern void cppInit (const boolean state, const boolean hasAtLiteralStrings,
+                     const boolean hasCxxRawLiteralStrings);
 extern void cppTerminate (void);
 extern void cppBeginStatement (void);
 extern void cppEndStatement (void);


Modified: tagmanager/ctags/read.c
13 lines changed, 13 insertions(+), 0 deletions(-)
===================================================================
@@ -501,6 +501,19 @@ extern int fileGetc (void)
     return c;
 }
 
+/* returns the nth previous character (0 meaning current), or def if nth cannot
+ * be accessed.  Note that this can't access previous line data. */
+extern int fileGetNthPrevC (unsigned int nth, int def)
+{
+	const unsigned char *base = (unsigned char *) vStringValue (File.line);
+	const unsigned int offset = File.ungetchIdx + 1 + nth;
+
+	if (File.currentLine != NULL && File.currentLine >= base + offset)
+		return (int) *(File.currentLine - offset);
+	else
+		return def;
+}
+
 extern int fileSkipToCharacter (int c)
 {
 	int d;


Modified: tagmanager/ctags/read.h
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -102,6 +102,7 @@ extern boolean fileOpen (const char *const fileName, const langType language);
 extern boolean fileEOF (void);
 extern void fileClose (void);
 extern int fileGetc (void);
+extern int fileGetNthPrevC (unsigned int nth, int def);
 extern int fileSkipToCharacter (int c);
 extern void fileUngetc (int c);
 extern const unsigned char *fileReadLine (void);


Modified: tagmanager/src/tm_source_file.c
70 lines changed, 54 insertions(+), 16 deletions(-)
===================================================================
@@ -35,6 +35,14 @@
 #include "tm_source_file.h"
 #include "tm_tag.h"
 
+typedef struct
+{
+	TMSourceFile public;
+	guint refcount;
+} TMSourceFilePriv;
+
+#define SOURCE_FILE_NEW(S) ((S) = g_slice_new(TMSourceFilePriv))
+#define SOURCE_FILE_FREE(S) g_slice_free(TMSourceFilePriv, (TMSourceFilePriv *) S)
 
 static TMSourceFile *current_source_file = NULL;
 
@@ -118,8 +126,7 @@ static int tm_source_file_tags(const tagEntryInfo *tag)
 /* Set the argument list of tag identified by its name */
 static void tm_source_file_set_tag_arglist(const char *tag_name, const char *arglist)
 {
-	guint count;
-	TMTag **tags, *tag;
+	guint i;
 
 	if (NULL == arglist ||
 		NULL == tag_name ||
@@ -128,13 +135,16 @@ static void tm_source_file_set_tag_arglist(const char *tag_name, const char *arg
 		return;
 	}
 
-	tags = tm_tags_find(current_source_file->tags_array, tag_name, FALSE, FALSE,
-			&count);
-	if (tags != NULL && count == 1)
+	/* going in reverse order because the tag was added recently */
+	for (i = current_source_file->tags_array->len; i > 0; i--)
 	{
-		tag = tags[0];
-		g_free(tag->arglist);
-		tag->arglist = g_strdup(arglist);
+		TMTag *tag = (TMTag *) current_source_file->tags_array->pdata[i - 1];
+		if (g_strcmp0(tag->name, tag_name) == 0)
+		{
+			g_free(tag->arglist);
+			tag->arglist = g_strdup(arglist);
+			break;
+		}
 	}
 }
 
@@ -199,12 +209,26 @@ static gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_
 GEANY_API_SYMBOL
 TMSourceFile *tm_source_file_new(const char *file_name, const char *name)
 {
-	TMSourceFile *source_file = g_new(TMSourceFile, 1);
-	if (TRUE != tm_source_file_init(source_file, file_name, name))
+	TMSourceFilePriv *priv;
+
+	SOURCE_FILE_NEW(priv);
+	if (TRUE != tm_source_file_init(&priv->public, file_name, name))
 	{
-		g_free(source_file);
+		SOURCE_FILE_FREE(priv);
 		return NULL;
 	}
+	priv->refcount = 1;
+	return &priv->public;
+}
+
+
+static TMSourceFile *tm_source_file_dup(TMSourceFile *source_file)
+{
+	TMSourceFilePriv *priv = (TMSourceFilePriv *) source_file;
+
+	g_return_val_if_fail(NULL != source_file, NULL);
+
+	g_atomic_int_inc(&priv->refcount);
 	return source_file;
 }
 
@@ -223,20 +247,34 @@ static void tm_source_file_destroy(TMSourceFile *source_file)
 	source_file->tags_array = NULL;
 }
 
-/** Frees a TMSourceFile structure, including all contents. Before calling this
- function the TMSourceFile has to be removed from the TMWorkspace. 
- @param source_file The source file to free.
+/** Decrements the reference count of @a source_file
+ *
+ * If the reference count drops to 0, then @a source_file is freed, including all contents.
+ * Make sure the @a source_file is already removed from any TMWorkSpace before the
+ * this happens.
+ * @param source_file The source file to free.
+ * @see tm_workspace_remove_source_file()
 */
 GEANY_API_SYMBOL
 void tm_source_file_free(TMSourceFile *source_file)
 {
-	if (NULL != source_file)
+	TMSourceFilePriv *priv = (TMSourceFilePriv *) source_file;
+
+	if (NULL != priv && g_atomic_int_dec_and_test(&priv->refcount))
 	{
 		tm_source_file_destroy(source_file);
-		g_free(source_file);
+		SOURCE_FILE_FREE(priv);
 	}
 }
 
+/** Gets the GBoxed-derived GType for TMSourceFile
+ *
+ * @return TMSourceFile type . */
+GEANY_API_SYMBOL
+GType tm_source_file_get_type(void);
+
+G_DEFINE_BOXED_TYPE(TMSourceFile, tm_source_file, tm_source_file_dup, tm_source_file_free);
+
 /* Parses the text-buffer or source file and regenarates the tags.
  @param source_file The source file to parse
  @param text_buf The text buffer to parse


Modified: tagmanager/src/tm_source_file.h
3 lines changed, 3 insertions(+), 0 deletions(-)
===================================================================
@@ -12,6 +12,7 @@
 
 #include <stdio.h>
 #include <glib.h>
+#include <glib-object.h>
 
 #ifndef LIBCTAGS_DEFINED
 typedef int langType;
@@ -44,6 +45,8 @@ typedef struct
 	GPtrArray *tags_array; /**< Sorted tag array obtained by parsing the object */
 } TMSourceFile;
 
+GType tm_source_file_get_type(void);
+
 TMSourceFile *tm_source_file_new(const char *file_name, const char *name);
 
 void tm_source_file_free(TMSourceFile *source_file);


Modified: tagmanager/src/tm_tag.c
154 lines changed, 89 insertions(+), 65 deletions(-)
===================================================================
@@ -17,6 +17,7 @@
 #include "read.h"
 #define LIBCTAGS_DEFINED
 #include "tm_tag.h"
+#include "tm_parser.h"
 
 
 #define TAG_NEW(T)	((T) = g_slice_new0(TMTag))
@@ -108,6 +109,8 @@ typedef struct
 {
 	guint *sort_attrs;
 	gboolean partial;
+	const GPtrArray *tags_array;
+	gboolean first;
 } TMSortOptions;
 
 static const char *s_tag_type_names[] = {
@@ -860,7 +863,7 @@ void tm_tags_remove_file_tags(TMSourceFile *source_file, GPtrArray *tags_array)
 			TMTag **found;
 			TMTag *tag = source_file->tags_array->pdata[i];
 
-			found = tm_tags_find(tags_array, tag->name, FALSE, TRUE, &tag_count);
+			found = tm_tags_find(tags_array, tag->name, FALSE, &tag_count);
 
 			for (j = 0; j < tag_count; j++)
 			{
@@ -1081,85 +1084,74 @@ static gpointer binary_search(gpointer key, gpointer base, size_t nmemb,
 	return NULL;
 }
 
-static TMTag **tags_search(const GPtrArray *tags_array, TMTag *tag,
-		gboolean tags_array_sorted, TMSortOptions *sort_options)
+static gint tag_search_cmp(gconstpointer ptr1, gconstpointer ptr2, gpointer user_data)
 {
-	if (tags_array_sorted)
-	{	/* fast binary search on sorted tags array */
-		return (TMTag **) binary_search(&tag, tags_array->pdata, tags_array->len, 
-			tm_tag_compare, sort_options);
-	}
-	else
-	{	/* the slow way: linear search (to make it a bit faster, search reverse assuming
-		 * that the tag to search was added recently) */
-		guint i;
-		TMTag **t;
-		for (i = tags_array->len; i > 0; i--)
+	gint res = tm_tag_compare(ptr1, ptr2, user_data);
+
+	if (res == 0)
+	{
+		TMSortOptions *sort_options = user_data;
+		const GPtrArray *tags_array = sort_options->tags_array;
+		TMTag **tag = (TMTag **) ptr2;
+
+		/* if previous/next (depending on sort options) tag equal, we haven't
+		 * found the first/last tag in a sequence of equal tags yet */
+		if (sort_options->first && ptr2 != &tags_array->pdata[0]) {
+			if (tm_tag_compare(ptr1, tag - 1, user_data) == 0)
+				return -1;
+		}
+		else if (!sort_options->first && ptr2 != &tags_array->pdata[tags_array->len-1])
 		{
-			t = (TMTag **) &tags_array->pdata[i - 1];
-			if (0 == tm_tag_compare(&tag, t, sort_options))
-				return t;
+			if (tm_tag_compare(ptr1, tag + 1, user_data) == 0)
+				return 1;
 		}
 	}
-	return NULL;
+	return res;
 }
 
 /*
  Returns a pointer to the position of the first matching tag in a (sorted) tags array.
- The passed array of tags should be already sorted by name for optimal performance. If
- \c tags_array_sorted is set to FALSE, it may be unsorted but the lookup will be slower.
- @param tags_array Tag array (may be sorted on name)
+ The passed array of tags must be already sorted by name (searched with binary search).
+ @param tags_array Tag array (sorted on name)
  @param name Name of the tag to locate.
  @param partial If TRUE, matches the first part of the name instead of doing exact match.
- @param tags_array_sorted If TRUE, the passed \c tags_array is sorted by name so it can be
- searched with binary search. Otherwise it is searched linear which is obviously slower.
  @param tagCount Return location of the matched tags.
 */
 TMTag **tm_tags_find(const GPtrArray *tags_array, const char *name,
-		gboolean partial, gboolean tags_array_sorted, guint * tagCount)
+		gboolean partial, guint *tagCount)
 {
-	static TMTag *tag = NULL;
-	TMTag **result;
-	guint tagMatches=0;
+	TMTag *tag, **first;
 	TMSortOptions sort_options;
 
 	*tagCount = 0;
-	if ((!tags_array) || (!tags_array->len))
+	if (!tags_array || !tags_array->len)
 		return NULL;
 
-	if (NULL == tag)
-		tag = g_new0(TMTag, 1);
+	tag = g_new0(TMTag, 1);
 	tag->name = (char *) name;
+
 	sort_options.sort_attrs = NULL;
 	sort_options.partial = partial;
+	sort_options.tags_array = tags_array;
+	sort_options.first = TRUE;
+	first = (TMTag **)binary_search(&tag, tags_array->pdata, tags_array->len,
+			tag_search_cmp, &sort_options);
 
-	result = tags_search(tags_array, tag, tags_array_sorted, &sort_options);
-	/* There can be matches on both sides of result */
-	if (result)
+	if (first)
 	{
-		TMTag **last = (TMTag **) &tags_array->pdata[tags_array->len - 1];
-		TMTag **adv;
-
-		/* First look for any matches after result */
-		adv = result;
-		adv++;
-		for (; adv <= last && *adv; ++ adv)
-		{
-			if (0 != tm_tag_compare(&tag, adv, &sort_options))
-				break;
-			++tagMatches;
-		}
-		/* Now look for matches from result and below */
-		for (; result >= (TMTag **) tags_array->pdata; -- result)
-		{
-			if (0 != tm_tag_compare(&tag, (TMTag **) result, &sort_options))
-				break;
-			++tagMatches;
-		}
-		*tagCount=tagMatches;
-		++ result;	/* Correct address for the last successful match */
+		TMTag **last;
+		unsigned first_pos;
+
+		sort_options.first = FALSE;
+		first_pos = first - (TMTag **)tags_array->pdata;
+		/* search between the first element and end */
+		last = (TMTag **)binary_search(&tag, first, tags_array->len - first_pos,
+				tag_search_cmp, &sort_options);
+		*tagCount = last - first + 1;
 	}
-	return (TMTag **) result;
+
+	g_free(tag);
+	return (TMTag **) first;
 }
 
 /* Returns TMTag which "own" given line
@@ -1190,17 +1182,48 @@ tm_get_current_tag (GPtrArray * file_tags, const gulong line, const TMTagType ta
 	return matching_tag;
 }
 
-#if 0
-/* Returns TMTag to function or method which "own" given line
- @param line Current line in edited file.
- @param file_tags A GPtrArray of edited file TMTag pointers.
- @return TMTag pointers to owner function. */
-static const TMTag *
-tm_get_current_function (GPtrArray * file_tags, const gulong line)
+const gchar *tm_tag_context_separator(langType lang)
 {
-	return tm_get_current_tag (file_tags, line, tm_tag_function_t | tm_tag_method_t);
+	switch (lang)
+	{
+		case TM_PARSER_C:	/* for C++ .h headers or C structs */
+		case TM_PARSER_CPP:
+		case TM_PARSER_GLSL:	/* for structs */
+		/*case GEANY_FILETYPES_RUBY:*/ /* not sure what to use atm*/
+		case TM_PARSER_PHP:
+		case TM_PARSER_POWERSHELL:
+		case TM_PARSER_RUST:
+		case TM_PARSER_ZEPHIR:
+			return "::";
+
+		/* avoid confusion with other possible separators in group/section name */
+		case TM_PARSER_CONF:
+		case TM_PARSER_REST:
+			return ":::";
+
+		/* no context separator */
+		case TM_PARSER_ASCIIDOC:
+		case TM_PARSER_TXT2TAGS:
+			return "\x03";
+
+		default:
+			return ".";
+	}
+}
+
+gboolean tm_tag_is_anon(const TMTag *tag)
+{
+	guint i;
+	char dummy;
+
+	if (tag->lang == TM_PARSER_C || tag->lang == TM_PARSER_CPP)
+		return sscanf(tag->name, "anon_%*[a-z]_%u%c", &i, &dummy) == 1;
+	else if (tag->lang == TM_PARSER_FORTRAN || tag->lang == TM_PARSER_F77)
+		return sscanf(tag->name, "Structure#%u%c", &i, &dummy) == 1 ||
+			sscanf(tag->name, "Interface#%u%c", &i, &dummy) == 1 ||
+			sscanf(tag->name, "Enum#%u%c", &i, &dummy) == 1;
+	return FALSE;
 }
-#endif
 
 
 #ifdef TM_DEBUG /* various debugging functions */
@@ -1343,11 +1366,12 @@ void tm_tags_array_print(GPtrArray *tags, FILE *fp)
 */
 gint tm_tag_scope_depth(const TMTag *t)
 {
+	const gchar *context_sep = tm_tag_context_separator(t->lang);
 	gint depth;
 	char *s;
 	if(!(t && t->scope))
 		return 0;
-	for (s = t->scope, depth = 0; s; s = strstr(s, "::"))
+	for (s = t->scope, depth = 0; s; s = strstr(s, context_sep))
 	{
 		++ depth;
 		++ s;


Modified: tagmanager/src/tm_tag.h
6 lines changed, 5 insertions(+), 1 deletions(-)
===================================================================
@@ -179,7 +179,7 @@ gboolean tm_tags_prune(GPtrArray *tags_array);
 gboolean tm_tags_dedup(GPtrArray *tags_array, TMTagAttrType *sort_attributes, gboolean unref_duplicates);
 
 TMTag **tm_tags_find(const GPtrArray *tags_array, const char *name,
-		gboolean partial, gboolean tags_array_sorted, guint * tagCount);
+		gboolean partial, guint * tagCount);
 
 void tm_tags_array_free(GPtrArray *tags_array, gboolean free_all);
 
@@ -191,6 +191,10 @@ TMTag *tm_tag_ref(TMTag *tag);
 
 gboolean tm_tags_equal(const TMTag *a, const TMTag *b);
 
+const gchar *tm_tag_context_separator(langType lang);
+
+gboolean tm_tag_is_anon(const TMTag *tag);
+
 #ifdef TM_DEBUG /* various debugging functions */
 
 const char *tm_tag_type_name(const TMTag *tag);


Modified: tagmanager/src/tm_workspace.c
898 lines changed, 336 insertions(+), 562 deletions(-)
===================================================================
@@ -32,6 +32,7 @@
 
 #include "tm_workspace.h"
 #include "tm_tag.h"
+#include "tm_parser.h"
 
 
 /* when changing, always keep the three sort criteria below in sync */
@@ -55,6 +56,9 @@ static TMTagAttrType global_tags_sort_attrs[] =
 	tm_tag_attr_type_t, tm_tag_attr_scope_t, tm_tag_attr_arglist_t, 0
 };
 
+static TMTagType TM_TYPE_WITH_MEMBERS =
+	tm_tag_class_t | tm_tag_struct_t | tm_tag_union_t |
+	tm_tag_enum_t | tm_tag_interface_t;
 
 static TMWorkspace *theWorkspace = NULL;
 
@@ -67,6 +71,7 @@ static gboolean tm_create_workspace(void)
 	theWorkspace->global_tags = g_ptr_array_new();
 	theWorkspace->source_files = g_ptr_array_new();
 	theWorkspace->typename_array = g_ptr_array_new();
+	theWorkspace->global_typename_array = g_ptr_array_new();
 	return TRUE;
 }
 
@@ -88,6 +93,7 @@ void tm_workspace_free(void)
 	tm_tags_array_free(theWorkspace->global_tags, TRUE);
 	g_ptr_array_free(theWorkspace->tags_array, TRUE);
 	g_ptr_array_free(theWorkspace->typename_array, TRUE);
+	g_ptr_array_free(theWorkspace->global_typename_array, TRUE);
 	g_free(theWorkspace);
 	theWorkspace = NULL;
 }
@@ -116,6 +122,16 @@ static void tm_workspace_merge_tags(GPtrArray **big_array, GPtrArray *small_arra
 }
 
 
+static void merge_extracted_tags(GPtrArray **dest, GPtrArray *src, TMTagType tag_types)
+{
+	GPtrArray *arr;
+
+	arr = tm_tags_extract(src, tag_types);
+	tm_workspace_merge_tags(dest, arr);
+	g_ptr_array_free(arr, TRUE);
+}
+
+
 static void update_source_file(TMSourceFile *source_file, guchar* text_buf,
 	gsize buf_size, gboolean use_buffer, gboolean update_workspace)
 {
@@ -134,16 +150,12 @@ static void update_source_file(TMSourceFile *source_file, guchar* text_buf,
 	tm_tags_sort(source_file->tags_array, file_tags_sort_attrs, FALSE, TRUE);
 	if (update_workspace)
 	{
-		GPtrArray *sf_typedefs;
-
 #ifdef TM_DEBUG
 		g_message("Updating workspace from source file");
 #endif
 		tm_workspace_merge_tags(&theWorkspace->tags_array, source_file->tags_array);
-		
-		sf_typedefs = tm_tags_extract(source_file->tags_array, TM_GLOBAL_TYPE_MASK);
-		tm_workspace_merge_tags(&theWorkspace->typename_array, sf_typedefs);
-		g_ptr_array_free(sf_typedefs, TRUE);
+
+		merge_extracted_tags(&(theWorkspace->typename_array), source_file->tags_array, TM_GLOBAL_TYPE_MASK);
 	}
 #ifdef TM_DEBUG
 	else
@@ -385,6 +397,9 @@ gboolean tm_workspace_load_global_tags(const char *tags_file, gint mode)
 	g_ptr_array_free(file_tags, TRUE);
 	theWorkspace->global_tags = new_tags;
 
+	g_ptr_array_free(theWorkspace->global_typename_array, TRUE);
+	theWorkspace->global_typename_array = tm_tags_extract(new_tags, TM_GLOBAL_TYPE_MASK);
+
 	return TRUE;
 }
 
@@ -671,667 +686,426 @@ gboolean tm_workspace_create_global_tags(const char *pre_process, const char **i
 }
 
 
-/* Returns all matching tags found in the workspace.
- @param name The name of the tag to find.
- @param type The tag types to return (TMTagType). Can be a bitmask.
- @param attrs The attributes to sort and dedup on (0 terminated integer array).
- @param partial Whether partial match is allowed.
- @param lang Specifies the language(see the table in parsers.h) of the tags to be found,
-             -1 for all
- @return Array of matching tags. Do not free() it since it is a static member.
-*/
-const GPtrArray *tm_workspace_find(const char *name, TMTagType type, TMTagAttrType *attrs,
-	gboolean partial, langType lang)
+static gboolean langs_compatible(langType lang, langType other)
 {
-	static GPtrArray *tags = NULL;
-	TMTag **matches[2];
-	size_t len;
-	guint tagCount[2]={0,0}, tagIter;
-
-	if (!name)
-		return NULL;
-	len = strlen(name);
-	if (!len)
-		return NULL;
-	if (tags)
-		g_ptr_array_set_size(tags, 0);
-	else
-		tags = g_ptr_array_new();
-
-	matches[0] = tm_tags_find(theWorkspace->tags_array, name, partial, TRUE,
-					&tagCount[0]);
-	matches[1] = tm_tags_find(theWorkspace->global_tags, name, partial, TRUE, &tagCount[1]);
-
-	/* file tags */
-	if (matches[0] && *matches[0])
-	{
-		for (tagIter=0;tagIter<tagCount[0];++tagIter)
-		{
-			gint tag_lang = (*matches[0])->lang;
-
-			if ((type & (*matches[0])->type) && (lang == -1 || tag_lang == lang))
-				g_ptr_array_add(tags, *matches[0]);
-			if (partial)
-			{
-				if (0 != strncmp((*matches[0])->name, name, len))
-					break;
-			}
-			else
-			{
-				if (0 != strcmp((*matches[0])->name, name))
-					break;
-			}
-			++ matches[0];
-		}
-	}
-
-	/* global tags */
-	if (matches[1] && *matches[1])
-	{
-		for (tagIter=0;tagIter<tagCount[1];++tagIter)
-		{
-			gint tag_lang = (*matches[1])->lang;
-			gint tag_lang_alt = 0;
-
-			/* tag_lang_alt is used to load C global tags only once for C and C++
-			 * lang = 1 is C++, lang = 0 is C
-			 * if we have lang 0, than accept also lang 1 for C++ */
-			if (tag_lang == 0)	/* C or C++ */
-				tag_lang_alt = 1;
-			else
-				tag_lang_alt = tag_lang; /* otherwise just ignore it */
-
-			if ((type & (*matches[1])->type) && (lang == -1 ||
-				tag_lang == lang || tag_lang_alt == lang))
-				g_ptr_array_add(tags, *matches[1]);
-
-			if (partial)
-			{
-				if (0 != strncmp((*matches[1])->name, name, len))
-					break;
-			}
-			else
-			{
-				if (0 != strcmp((*matches[1])->name, name))
-					break;
-			}
-			++ matches[1];
-		}
-	}
+	if (lang == other || lang == -1 || other == -1)
+		return TRUE;
+	/* Accept CPP tags for C lang and vice versa */
+	else if (lang == TM_PARSER_C && other == TM_PARSER_CPP)
+		return TRUE;
+	else if (lang == TM_PARSER_CPP && other == TM_PARSER_C)
+		return TRUE;
 
-	if (attrs)
-		tm_tags_sort(tags, attrs, TRUE, FALSE);
-	return tags;
-}
-
-
-static gboolean match_langs(gint lang, const TMTag *tag)
-{
-	if (tag->file)
-	{	/* workspace tag */
-		if (lang == tag->file->lang)
-			return TRUE;
-	}
-	else
-	{	/* global tag */
-		if (lang == tag->lang)
-			return TRUE;
-	}
 	return FALSE;
 }
 
 
-/* scope can be NULL.
- * lang can be -1 */
-static guint
-fill_find_tags_array (GPtrArray *dst, const GPtrArray *src,
-					  const char *name, const char *scope, TMTagType type, gboolean partial,
-					  gint lang, gboolean first)
+static void fill_find_tags_array(GPtrArray *dst, const GPtrArray *src,
+	const char *name, const char *scope, TMTagType type, langType lang)
 {
-	TMTag **match;
-	guint tagIter, count;
+	TMTag **tag;
+	guint i, num;
 
-	if ((!src) || (!dst) || (!name) || (!*name))
-		return 0;
+	if (!src || !dst || !name || !*name)
+		return;
 
-	match = tm_tags_find (src, name, partial, TRUE, &count);
-	if (count && match && *match)
+	tag = tm_tags_find(src, name, FALSE, &num);
+	for (i = 0; i < num; ++i)
 	{
-		for (tagIter = 0; tagIter < count; ++tagIter)
+		if ((type & (*tag)->type) &&
+			langs_compatible(lang, (*tag)->lang) &&
+			(!scope || g_strcmp0((*tag)->scope, scope) == 0))
 		{
-			if (! scope || (match[tagIter]->scope &&
-				0 == strcmp(match[tagIter]->scope, scope)))
-			{
-				if (type & match[tagIter]->type)
-				if (lang == -1 || match_langs(lang, match[tagIter]))
-				{
-					g_ptr_array_add (dst, match[tagIter]);
-					if (first)
-						break;
-				}
-			}
+			g_ptr_array_add(dst, *tag);
 		}
+		tag++;
 	}
-	return dst->len;
 }
 
 
-/* Returns all matching tags found in the workspace. Adapted from tm_workspace_find, Anjuta 2.02
+/* Returns all matching tags found in the workspace.
  @param name The name of the tag to find.
  @param scope The scope name of the tag to find, or NULL.
  @param type The tag types to return (TMTagType). Can be a bitmask.
  @param attrs The attributes to sort and dedup on (0 terminated integer array).
- @param partial Whether partial match is allowed.
  @param lang Specifies the language(see the table in parsers.h) of the tags to be found,
              -1 for all
- @return Array of matching tags. Do not free() it since it is a static member.
+ @return Array of matching tags.
 */
-const GPtrArray *
-tm_workspace_find_scoped (const char *name, const char *scope, TMTagType type,
-		TMTagAttrType *attrs, gboolean partial, langType lang, gboolean global_search)
+GPtrArray *tm_workspace_find(const char *name, const char *scope, TMTagType type,
+	TMTagAttrType *attrs, langType lang)
 {
-	static GPtrArray *tags = NULL;
+	GPtrArray *tags = g_ptr_array_new();
 
-	if (tags)
-		g_ptr_array_set_size (tags, 0);
-	else
-		tags = g_ptr_array_new ();
+	fill_find_tags_array(tags, theWorkspace->tags_array, name, scope, type, lang);
+	fill_find_tags_array(tags, theWorkspace->global_tags, name, scope, type, lang);
 
-	fill_find_tags_array (tags, theWorkspace->tags_array,
-						  name, scope, type, partial, lang, FALSE);
-	if (global_search)
-	{
-		/* for a scoped tag, I think we always want the same language */
-		fill_find_tags_array (tags, theWorkspace->global_tags,
-							  name, scope, type, partial, lang, FALSE);
-	}
 	if (attrs)
-		tm_tags_sort (tags, attrs, TRUE, FALSE);
+		tm_tags_sort(tags, attrs, TRUE, FALSE);
+
 	return tags;
 }
 
 
-static int
-find_scope_members_tags (const GPtrArray * all, GPtrArray * tags,
-						 const langType langJava, const char *name,
-						 const char *filename, gboolean no_definitions)
+static void fill_find_tags_array_prefix(GPtrArray *dst, const GPtrArray *src,
+	const char *name, langType lang, guint max_num)
 {
-	GPtrArray *local = g_ptr_array_new ();
-	unsigned int i;
-	TMTag *tag;
-	size_t len = strlen (name);
-	for (i = 0; (i < all->len); ++i)
+	TMTag **tag, *last = NULL;
+	guint i, count, num;
+
+	if (!src || !dst || !name || !*name)
+		return;
+
+	num = 0;
+	tag = tm_tags_find(src, name, TRUE, &count);
+	for (i = 0; i < count && num < max_num; ++i)
 	{
-		tag = TM_TAG (all->pdata[i]);
-		if (no_definitions && filename && tag->file &&
-			0 != strcmp (filename,
-						 tag->file->short_name))
-		{
-			continue;
-		}
-		if (tag && tag->scope && tag->scope[0] != '\0')
+		if (langs_compatible(lang, (*tag)->lang) &&
+			!tm_tag_is_anon(*tag) &&
+			(!last || g_strcmp0(last->name, (*tag)->name) != 0))
 		{
-			if (0 == strncmp (name, tag->scope, len))
-			{
-				g_ptr_array_add (local, tag);
-			}
+			g_ptr_array_add(dst, *tag);
+			last = *tag;
+			num++;
 		}
+		tag++;
 	}
-	if (local->len > 0)
-	{
-		unsigned int j;
-		TMTag *tag2;
-		char backup = 0;
-		char *s_backup = NULL;
-		char *var_type = NULL;
-		char *scope;
-		for (i = 0; (i < local->len); ++i)
-		{
-			tag = TM_TAG (local->pdata[i]);
-			scope = tag->scope;
-			if (scope && 0 == strcmp (name, scope))
-			{
-				g_ptr_array_add (tags, tag);
-				continue;
-			}
-			s_backup = NULL;
-			j = 0;				/* someone could write better code :P */
-			while (scope)
-			{
-				if (s_backup)
-				{
-					backup = s_backup[0];
-					s_backup[0] = '\0';
-					if (0 == strcmp (name, tag->scope))
-					{
-						j = local->len;
-						s_backup[0] = backup;
-						break;
-					}
-				}
-				if (tag->file
-					&& tag->file->lang == langJava)
-				{
-					scope = strrchr (tag->scope, '.');
-					if (scope)
-						var_type = scope + 1;
-				}
-				else
-				{
-					scope = strrchr (tag->scope, ':');
-					if (scope)
-					{
-						var_type = scope + 1;
-						scope--;
-					}
-				}
-				if (s_backup)
-				{
-					s_backup[0] = backup;
-				}
-				if (scope)
-				{
-					if (s_backup)
-					{
-						backup = s_backup[0];
-						s_backup[0] = '\0';
-					}
-					for (j = 0; (j < local->len); ++j)
-					{
-						if (i == j)
-							continue;
-						tag2 = TM_TAG (local->pdata[j]);
-						if (tag2->var_type &&
-							0 == strcmp (var_type, tag2->var_type))
-						{
-							break;
-						}
-					}
-					if (s_backup)
-						s_backup[0] = backup;
-				}
-				if (j < local->len)
-				{
-					break;
-				}
-				s_backup = scope;
-			}
-			if (j == local->len)
-			{
-				g_ptr_array_add (tags, tag);
-			}
-		}
-	}
-	g_ptr_array_free (local, TRUE);
-	return (int) tags->len;
 }
 
 
-/* Returns all matching members tags found in given struct/union/class name.
- @param name Name of the struct/union/class.
- @param file_tags A GPtrArray of edited file TMTag pointers (for search speedup, can be NULL).
- @return A GPtrArray of TMTag pointers to struct/union/class members */
-const GPtrArray *
-tm_workspace_find_scope_members (const GPtrArray * file_tags, const char *name,
-								 gboolean search_global, gboolean no_definitions)
+/* Returns tags with the specified prefix sorted by name. If there are several
+ tags with the same name, only one of them appears in the resulting array.
+ @param prefix The prefix of the tag to find.
+ @param lang Specifies the language(see the table in parsers.h) of the tags to be found,
+             -1 for all.
+ @param max_num The maximum number of tags to return.
+ @return Array of matching tags sorted by their name.
+*/
+GPtrArray *tm_workspace_find_prefix(const char *prefix, langType lang, guint max_num)
 {
-	static GPtrArray *tags = NULL;
-	GPtrArray *local = NULL;
-	char *new_name = (char *) name;
-	char *filename = NULL;
-	int found = 0, del = 0;
-	static langType langJava = -1;
-	TMTag *tag = NULL;
-
-	/* FIXME */
-	/* langJava = getNamedLanguage ("Java"); */
+	TMTagAttrType attrs[] = { tm_tag_attr_name_t, 0 };
+	GPtrArray *tags = g_ptr_array_new();
 
-	g_return_val_if_fail ((theWorkspace && name && name[0] != '\0'), NULL);
+	fill_find_tags_array_prefix(tags, theWorkspace->tags_array, prefix, lang, max_num);
+	fill_find_tags_array_prefix(tags, theWorkspace->global_tags, prefix, lang, max_num);
 
-	if (!tags)
-		tags = g_ptr_array_new ();
+	tm_tags_sort(tags, attrs, TRUE, FALSE);
+	if (tags->len > max_num)
+		tags->len = max_num;
 
-	while (1)
-	{
-		const GPtrArray *tags2;
-		guint got = 0;
-		TMTagType types = (tm_tag_class_t | tm_tag_namespace_t |
-						   tm_tag_struct_t | tm_tag_typedef_t |
-						   tm_tag_union_t | tm_tag_enum_t);
+	return tags;
+}
 
-		if (file_tags)
-		{
-			g_ptr_array_set_size (tags, 0);
-			got = fill_find_tags_array (tags, file_tags,
-										  new_name, NULL, types, FALSE, -1, FALSE);
-		}
-		if (got)
-		{
-			tags2 = tags;
-		}
-		else
-		{
-			TMTagAttrType attrs[] = {
-				tm_tag_attr_name_t, tm_tag_attr_type_t,
-				tm_tag_attr_none_t
-			};
-			tags2 = tm_workspace_find (new_name, types, attrs, FALSE, -1);
-		}
 
-		if ((tags2) && (tags2->len == 1) && (tag = TM_TAG (tags2->pdata[0])))
-		{
-			if (tag->type == tm_tag_typedef_t && tag->var_type
-				&& tag->var_type[0] != '\0')
-			{
-				char *tmp_name;
-				tmp_name = tag->var_type;
-				if (strcmp(tmp_name, new_name) == 0) {
-					new_name = NULL;
-				}
-				else {
-					new_name = tmp_name;
-				}
-				continue;
-			}
-			filename = (tag->file ?
-						tag->file->short_name : NULL);
-			if (tag->scope && tag->scope[0] != '\0')
-			{
-				del = 1;
-				if (tag->file &&
-					tag->file->lang == langJava)
-				{
-					new_name = g_strdup_printf ("%s.%s",
-												tag->scope,
-												new_name);
-				}
-				else
-				{
-					new_name = g_strdup_printf ("%s::%s",
-												tag->scope,
-												new_name);
-				}
-			}
-			break;
-		}
-		else
-		{
-			return @@ Diff output truncated at 100000 characters. @@

--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list