I'm not sure how robust our parser is against invalid input or updated ctags file format so better use the upstream version of the official library to parse ctags files so we don't have to worry about this.
In addition, this patch also updates the code to read all the ctags kinds we need in tagmanager. You can view, comment on, or merge this pull request online at:
https://github.com/geany/geany/pull/3049
-- Commit Summary --
* Add ctags 'readtags' library to allow us parse ctags files * Use the readtags library to parse ctags files
-- File Changes --
M ctags/Makefile.am (2) A ctags/libreadtags/readtags.c (1310) A ctags/libreadtags/readtags.h (295) M src/tagmanager/Makefile.am (1) M src/tagmanager/tm_source_file.c (174)
-- Patch Links --
https://github.com/geany/geany/pull/3049.patch https://github.com/geany/geany/pull/3049.diff
While you improve the tag loading, would it be possible to also add support for function arguments? If I look correctly, those are not currently processed from ctags, but Geany uses them when they're in tagmanager format.
Ctags do support that, at least for some languages (e.g.: C, Python but probably many others). The only problem is that it is not in the default ctags output format, it must be requested on the command line.
but Geany uses them when they're in tagmanager format
I don't think tagmanager actually handles parameters as such, it handles the whole argument list as a single string IIRC so you can't access the parameter names.
The new C/C++ parser can parse locals and parameters IIUC, see #3032 and associated discussion. Geany (and ctags??) has no way of specifying scope for these because the scope is lexical not named like structure and class members. So they appear everywhere, not restricted to the appropriate function. So #3032 disables them by default until that problem is solved.
While you improve the tag loading, would it be possible to also add support for function arguments? If I look correctly, those are not currently processed from ctags, but Geany uses them when they're in tagmanager format.
It is the "signature" field and it was processed before and should be handled by this patch too. I tried to go through all the flags ctags offers and use all the information that might be useful for Geany. What was missing before was the "typeref" field that provides variable types and function return values and this is now included in this patch.
I don't think tagmanager actually handles parameters as such, it handles the whole argument list as a single string IIRC so you can't access the parameter names.
Ah, ok, maybe I misunderstood the question - if it's about extracting arguments as separate tags, this is just about enabling this feature in Geany but it needs some extra work on Geany side which hasn't been done yet.
Geany (and ctags??) has no way of specifying scope for these because the scope is lexical not named like structure and class members. So they appear everywhere, not restricted to the appropriate function.
The scope is actually included correctly, we just don't take it into account and it has to be fixed at various places (should be pretty easy).
Ah, ok, maybe I misunderstood the question
Or I did ;-P
The scope is actually included correctly
Oh, ok, its a range of lines is it?
Oh, ok, its a range of lines is it?
Well, the function name is included in the scope of local variables. So e.g. for ``` int main(void) { int i; for (i = 0; i < 10; i++) { int j; } } ``` the scope for `i` is `main`. Now of course you won't see any nested blocks so `j` will have the same scope as `i` but at least you can distinguish what's local for the function and what isn't.
the scope for i is main.
So the problem in Geany is we don't know the lexical scope of main, let alone use that to filter what names are visible?
So the problem in Geany is we don't know the lexical scope of main, let alone use that to filter what names are visible?
The problem (and it's not really a problem, it's just not done yet) is: 1. For normal autocompletion we currently include all tags - you want those because even if they refer to a tag nested in some type, this is what you might to want to get autocompleted. Now, when you enable parsing of functions, you of course don't want tags defined in other functions than the one you are editing so these have to be excluded. 2. For going to tag definition/declaration it's more or less like (1). 3. For scope autocompletion the code should be adjusted that when determining variable type, it should first check the tags for variables defined in the current function and only afterwards look at global variable definitions (plus exclude variables defined in other functions). Also we currently don't use inheritance information at all so you only get tags defined in the class for which the variable is declared but not from superclasses. 4. For the symbol tree we should exclude local variables and function parameters.
Or in other words - the scope information is only used to detect how types are nested and what to show when `.` is typed, but the current scope (i.e. where the cursor is placed) isn't used for scope completion at all. We didn't do that because we had only tags at the global scope and it's not really easy to determine where you are (e.g. C++ namespaces can span multiple files, `using namespace` can be used etc.). But when function parsing is enabled, you can easily tell if you are inside a function of certain name or not and what tags are defined inside that function.
Nothing from the above is really hard to do (maybe traversing the inheritance tree might be a bit tricky but can be added later), it just has some consequences on some aspects of Geany that I'd like to address first: 1. The easiest way to add local variables would be introducing a new entry for them to https://github.com/geany/geany/blob/d031d6f2fcb12e9670dade20fc9a657dedb5a5c2... 2. We also might need to change the mappings to members of the above enum for some languages because this information is critical for scope completion to work correctly. This is why I suggested doing this https://github.com/geany/geany/pull/3032#issuecomment-987984980 to be able to do it independently of how the tags are shown in the sidebar (and to start working on this requires that all the parsers are in to avoid modifying the same code and introducing merge conflicts). 3. The problem with (1) and (2) is that once we start modifying our mappings, we make the binary Geany tags files incompatible between Geany releases. This is why I suggested switching to the ctags file format because it doesn't contain the information about our internal mappings and then we can do whatever we want with the mappings. It doesn't mean that we should remove tag generation from Geany - we can still keep it but generate tags in the ctags format for users by default (and use the binary format for unit tests because there we want to see the mapped values).
I created new `tag-manager` label so expect a few pull requests with this label ;-).
The problem (and it's not really a problem, it's just not done yet) is: 1. For normal autocompletion we currently include all tags
Actually this is _the_ __Problem__ (bold and capital P :-) and it makes autocomplete pretty much useless currently.
you want those because even if they refer to a tag nested in some type, this is what you might to want to get autocompleted
Sure as you say, currently without locals and parameters its mostly impossible to deduce scope (globals only) so dumping in everything and the kitchen sink is the only solution, but as you say that could be improved with newer parsers. But lexical scope is also needed because some pesky languages that are not C also have other names from the class definition visible within member functions (eg C++ member functions see all data members or Python "self" sees the class members). So if I understand you correctly the new parsers will give us a proper lexical scope (at least for function levels if not internal scopes) so we no longer need the hack of trying to align folds and declarations, and then it should be possible to reduce the noise a lot.
- For going to tag definition/declaration it's more or less like (1).
Well while we are at it, why not lump some more work on you, can we have a method of distinguishing overloads ;-) A single name is often declared and defined multiple times, eg `size()` is likely the most common name in C++, nearly everything has it (closely followed by `get()` and `set()`).
- For scope autocompletion the code should be adjusted that when determining variable type, it should first check the tags for variables defined in the current function and only afterwards look at global variable definitions (plus exclude variables defined in other functions).
Yes if the language says local names hide the global ones, but beware the C++ `::name` that sees the global one, or Julia `global x` that does the same.
Also we currently don't use inheritance information at all so you only get tags defined in the class for which the variable is declared but not from superclasses.
Nor (as I ranted above) do we see members defined in classes which are automagically visible in member functions (for C++, or with "self" for Python or Rust) before inheritance is even considered. And that of course means identifying if a function is a member function/method or just a "plain function".
- For the symbol tree we should exclude local variables and function parameters.
Yep, agreed.
Nothing from the above is really hard to do
The Clang guys would be surprised to hear that ;-)
(maybe traversing the inheritance tree might be a bit tricky but can be added later), it just has some consequences on some aspects of Geany that I'd like to address first:
Please note I am not just being annoying by bringing up the difficulties, exceptions, and issues above, I want to make sure all the weirdness of various languages are considered first so it can be implemented progressively, otherwise the first apparently simple solutions will block some of the more subtle later capabilities when you come to add them, and stuff will have to be undone or re-done leading to many massive PRs again, all with the `tag-manager` label :grin:
Maybe we should move this part of the discussion to a separate issue or github discussion rather than have it spread across several PRs like this that are only tangentially related.
So if I understand you correctly the new parsers will give us a proper lexical scope (at least for function levels if not internal scopes) so we no longer need the hack of trying to align folds and declarations, and then it should be possible to reduce the noise a lot.
To be clear, I think right now it's only the C/C++ parser that parses function bodies and it may be the only parser that will ever do it. I think it was out of necessity as C/C++ are impossible to parse correctly without them (something that @dolik-rce did run into with the Kotlin parser too). Local variables were then thrown in as a bonus. But I don't think this is the feature that is in general planned for other parsers in ctags. And even if e.g. the Python parser started parsing function bodies, we are more or less blind regarding types in dynamically typed languages and those will be useless for scope completion.
Well while we are at it, why not lump some more work on you, can we have a method of distinguishing overloads ;-)
Since the popup with autocompletion shows only names and not parameters and this list is made not to contain duplicates, there's no work for me :-). In the tooltip after opening a brace you can already switch among alternatives).
Yes if the language says local names hide the global ones, but beware the C++ ::name that sees the global one, or Julia global x that does the same. Nor (as I ranted above) do we see members defined in classes which are automagically visible in member functions (for C++, or with "self" for Python or Rust) before inheritance is even considered. And that of course means identifying if a function is a member function/method or just a "plain function".
This is just too language specific and there are too many things like these to handle in general in the scope completion code I'm afraid.
The Clang guys would be surprised to hear that ;-)
Let's be clear - what we are talking here about for Geany is stupid and naive scope completion (that doesn't behave in an annoying manner though). I myself don't plan doing anything advanced because I think (1) it's extremely complicated to achieve using plain tag lists instead of syntax tree with semantic annotations (2) it's a waste of time when things like https://microsoft.github.io/language-server-protocol/ exist which we should rather support in Geany to take over all the tag manager stuff when installed and which will achieve much better results.
But despite being stupid and naive, I think we can still show some useful results in many cases.
Please note I am not just being annoying by bringing up the difficulties, exceptions, and issues above, I want to make sure all the weirdness of various languages are considered first so it can be implemented progressively, otherwise the first apparently simple solutions will block some of the more subtle later capabilities when you come to add them, and stuff will have to be undone or re-done leading to many massive PRs again, all with the tag-manager label 😁
Once again, I don't plan doing much in this area myself - apart from addition of inheritance information I would just make sure that tags from other functions don't appear in the results.
Primarily, I want to make some things that "feel right" regarding the tag manager so it's easy to add and update parsers, add new kinds, do some language-specific things at a single place so we don't run into the maintenance disaster we were before once again. If Geany can just update Scintilla and ctags easily and add support of new languages easily, we can have a new release "for free" even if we don't have much time to do something ourselves.
While you improve the tag loading, would it be possible to also add support for function arguments? If I look correctly, those are not currently processed from ctags, but Geany uses them when they're in tagmanager format.
It is the "signature" field and it was processed before and should be handled by this patch too.
Yes, I meant function signature, which should be parsed into `tag->arglist`. I must be getting blind, now I see it in both old and new code. Sorry, for confusion.
it's a waste of time when things like https://microsoft.github.io/language-server-protocol/ exist which we should rather support in Geany to take over all the tag manager stuff when installed and which will achieve much better results.
Agreed, but if only there was a way for it to actually take over, because so much is hard wired to tagmanager its difficult to do so, look at previous experiments with libclang.
Since the popup with autocompletion shows only names and not parameters and this list is made not to contain duplicates, there's no work for me :-). In the tooltip after opening a brace you can already switch among alternatives).
Ahh, I meant for goto declaration/definition not autocompletion.
Agreed, but if only there was a way for it to actually take over, because so much is hard wired to tagmanager its difficult to do so, look at previous experiments with libclang.
I don't think it's that bad - the biggest problem of previous attempts was they didn't clean the mess of tag manager itself first and tried to implement it on top of what's there right now. The biggest offender is `symbols.c` where many things could just be moved into tag manager and hidden behind appropriate API. I think the best way to go forward would be introducing a LSP-like API to tag manager for certain things and then switching between tag-manager-LSP and real LSP wouldn't be that hard. TMTag could be used for passing symbol data both by tag manager and LSP (if we needed some extra info from LSP, we could add some `priv` pointer to it where extra details could be stored). Also, to simplify things I think we could also keep tag manager running even with LSP enabled, just not use tags from it for symbol tree, autocompletion, navigation etc.
The biggest offender is symbols.c where many things could just be moved into tag manager and hidden behind appropriate API. I think the best way to go forward would be introducing a LSP-like API to tag manager
Sounds plausible.
TMTag could be used for passing symbol data both by tag manager and LSP
Well, a struct called TMTag, but what it contains might be different :-)
I think we could also keep tag manager running even with LSP enabled
Well, the decision to use ctags/tm or LSP should be per document, IIUC not all languages have LSP available. What did you think would be the gain in still ctags parsing documents that are using LSP?
Well, a struct called TMTag, but what it contains might be different :-)
Well, even with LSP the stuff we store there now could be similar (and should be similar to make it compatible with existing code in Geany). But there might (and should) be some extra information stored there for sure.
Well, the decision to use ctags/tm or LSP should be per document, IIUC not all languages have LSP available. What did you think would be the gain in still ctags parsing documents that are using LSP?
For instance tag manager is exposed to plugins right now and plugins expect tag manager to work. Or there may be some minor features like the scope information in the status bar for which I think there is no counterpart in LSP (but the API is big and I might have missed it).
But most importantly, I think this feature has no chance to be merged if it's introduced as one giant pull request changing thousands of lines across Geany. It has to happen piece by piece. So for instance it could start by changing `tag_manager->get_symbols_for_symbol_tree()` to `LSP->get_symbols_for_symbol_tree()` and making sure this particular feature works and then moving to the next. Basically the API in LSP we are interested in most is - [completion](https://microsoft.github.io/language-server-protocol/specifications/specific...) - getting symbols for autocompletion popup - [signatureHelp](https://microsoft.github.io/language-server-protocol/specifications/specific...) - calltips - [declaration](https://microsoft.github.io/language-server-protocol/specifications/specific...) - go to declaration - [definition](https://microsoft.github.io/language-server-protocol/specifications/specific...) - go to definition - [documentSymbol](https://microsoft.github.io/language-server-protocol/specifications/specific...) - symbols for symbol tree
If we have similar API in tag manager (and this is really just a matter of moving some code from Geany to tag manager), changes to Geany code would be minimal to start playing with the corresponding LSP counterpart while keeping the rest of Geany unchanged and stable. If in the future we determine we can disable tag manager for files managed by LSP, we can of course do that (but before that we have to introduce corresponding API for plugins and make sure that there really isn't anything we depend on in tag manager).
Seems there is overlap between LSP and Scintilla as well?
If we do this (I would love to see at least a usable prototype as a base to make decisions) we should probably track progress via a Github project.
For instance tag manager is exposed to plugins right now and plugins expect tag manager to work.
Yes, thats an issue, perhaps there needs to be a migration to a common API over time. Of course with LSP the work that project plugins need to do is significantly reduced :stuck_out_tongue:
scope information in the status bar
Vscode shows current scope (in the top bar) the same way as Geany does in status, and it uses cpptools LSP server IIUC, so probably its possible.
I think this feature has no chance to be merged if it's introduced as one giant pull request changing thousands of lines across Geany. It has to happen piece by piece.
Fair enough, allowing progressive implementation is a valid reason.
we should probably track progress via a Github project.
Yes, and in a separate branch in the main repository, not a personal (Github) fork.
Yes, and in a separate branch in the main repository, not a personal (Github) fork.
Good, the plan is here. Maybe just one more tiny detail - we might also need someone who does the job :-). While this is something I would find tempting to do, this is quite a project and I'm definitely not going to start working on this in the short term myself.
Seems there is overlap between LSP and Scintilla as well?
Yes, there seems to be. But it's up to us what particular feature of LSP we would use or not.
If we do this (I would love to see at least a usable prototype as a base to make decisions) we should probably track progress via a Github project.
To implement the protocol itself, the easiest thing would be to steal some other editor's code for this. One then has to propagate some events from Geany to LSP - most importantly notifications about changes to the current document. This information can be incremental but for such a prototype it could be brute-force sending the whole document to LSP after every typed letter.
To implement the protocol itself, the easiest thing would be to steal some other editor's code for this.
MS didn't list any, but are there client SDKs/libraries?
Also what might be a bit of an issue is the fact that LSP is asynchronous, and Geany is resolutely synchronous.
MS didn't list any, but are there client SDKs/libraries?
There are some clients listed here at the bottom https://langserver.org
Also what might be a bit of an issue is the fact that LSP is asynchronous, and Geany is resolutely synchronous.
Could be converted to synchronous - i.e. blocking until response from the server is received. Of course the question is whether that would be fast enough.
Could be converted to synchronous - i.e. blocking until response from the server is received. Of course the question is whether that would be fast enough.
Since vscode is electron its hard to tell if visible delays are due to electron, or the server, or on a timer (like our ctags). Some things are pretty quick, like showing a popup with a symbol definition, if its that fast it might be ok although thats only a lookup, and in only a single file 200 line C++ example I'm using. But some things are slow, like highlighting, which can take about a second or two, that may be a timer or simply thats how long the server takes to do a proper compiler anaylsis of the syntax and semantics and respond. Either way its too slow for in-typing use if synchronous.
Of course I'm running it on a medium speed machine, worth a try on your Rpi.
But none of this is relevant to using libreadtags which seems a fine idea.
There are some clients listed here
Yeah, I was hoping for libraries, not having to adapt a client internals, tagmanager 2.0 anyone??
But some things are slow, like highlighting, which can take about a second or two, that may be a timer or simply thats how long the server takes to do a proper compiler anaylsis of the syntax and semantics and respond.
Depends what we use the language server for. The only thing that really sucks with tag manager right now in my opinion is autocompletion - the rest is quite fine. So initially the usage of LSP could concentrate on that.
Yeah, I was hoping for libraries, not having to adapt a client internals, tagmanager 2.0 anyone??
It took just about 15 years to recover from tag manager integration and we are almost there. We should start thinking about what to do in another 15 years :-).
But if LSP usage is limited to some features only, it may turn out that implementing it as a plugin is enough. I think initially though for some working prototype it would be best to hack it directly into Geany to know what API might be missing and decide based on that.
No matter whether we take some client code from somewhere or implement our own, there will have to be some JSON parser/serializer (json-glib seems to be a natural choice) in its core that will have to be either bundled or an external dependency - not sure if it's fine or not for Geany, for plugin it would be a easier decision.
But none of this is relevant to using libreadtags which seems a fine idea.
Yeah, back on earth, tag manager is what we have. The rosy world of LSP autocompletion for me is just an excuse why not improve the scary tag-manager-based scope completion much :-).
Depends what we use the language server for.
Well, apart from the autocomplete which I agree is just so wrong (for C++) that I turn it off in Geany, the other big reason I moved away (for C++) is the styling of a name the same wherever it appears, so if something ever appears as a type its gonna be coloured a type even when used for a function, or a variable no matter if its in a totally different scope. So I would say that replacing the Scintilla lexer would be a good thing to aspire to ... longer term maybe.
It took just about 15 years to recover from tag manager integration and we are almost there. We should start thinking about what to do in another 15 years :-)
Good idea!!!!! [runs screaming]
But synchronous operation is going to be slow, even for autocomplete. Think of how long it takes to compile one of the big Scintilla C++ files, especially on a RPi, would you wait that long to get the autocomplete list?
Why does autocomplete need a full compile? Doesn't need code generation, but needs everything before it and type inference is why, rust and go and others already do static inference, and C++ is starting to (which is why I keep using C++ as an example, it manages to incorporate every problem other static languages could give us, plus some of its own, ahh bless :-) and in theory an LSP server could do dynamic typing of Julia and maybe even Python and similar. To autocomplete a name with inferred type the "compile" has to happen to find its type, then the member list can be offered.
So we want the "compile" to happen while the user is typing so the lookup is fast when they type the `->`.
there will have to be some JSON parser/serializer (json-glib seems to be a natural choice) in its core that will have to be either bundled or an external dependency - not sure if it's fine or not for Geany, for plugin it would be a easier decision.
JSON is one thing where there are a plethora of libraries, and JSON RPC libraries even. But yes putting such in a plugin would be "easier" if only Geany would let a plugin replace parts of its functionality. Maybe a core plugin could keep in sync with Geany during a progressive development, maybe.
The rosy world of LSP autocompletion for me is just an excuse why not improve the scary tag-manager-based scope completion much :-).
Good, keeps the number of PRs labelled `tag-manager` down. ;-P
I havn't tried this PR because I'm not sure how to test it, do you have any solid examples of ctags files, especially one that the existing parser fails on?
I havn't tried this PR because I'm not sure how to test it, do you have any solid examples of ctags files, especially one that the existing parser fails on?
From looking at the code I think the Geany parser didn't handle escaping of some special characters so if they were present in ctags files, they didn't get unescaped. I mainly switched to the libreadtags library so the code gets simpler for us and we don't have to care about details of the ctags file format ourselves.
Not related to parsing the ctags file, I also wanted to get the `typeref` field from tag files so we have function return values and variable types and also get `extras` for anonymous tag information (not used for anything in this patch, it waits for my anonymous tag handling patches).
... the other big reason I moved away (for C++) is the styling of a name the same wherever it appears, so if something ever appears as a type its gonna be coloured a type even when used for a function, or a variable no matter if its in a totally different scope.
Just remembered I forgot to reply to this one - this is not a Scintilla thing. It's again tag manager (or more precisely `symbols.c`) which injects all type names from tag manager into Scintilla as a list of fake keywords. While it may be a problem to determine scopes correctly and when to do this and when not, it should be no problem to make this behavior configurable.
this is not a Scintilla thing. It's again tag manager (or more precisely symbols.c) which injects all type names from tag manager into Scintilla as a list of fake keywords.
Well, thats because its the only way of setting names to be styled in Lexilla lexers, to give the same name a different style in different scopes would need to drop the Lexilla lexer or have a way of the lexer allowing overwriting by semantic styling and not keep undoing it.
@techee pushed 3 commits.
f682792c645899654b429aec52fe48192a7fa18e Determine scope key based on the used kind name af445197e2b482f627679f1ee8aa8e3ccbd3cd56 Avoid unnecessary allocation eade946a9806795c5b31cf6f738e45dca74f9d55 Fix compilation when TM_DEBUG is defined
@techee pushed 1 commit.
67601b70a72be30a5b1b8efcf8b124600893f808 Fix scope key determination
@techee pushed 1 commit.
4b16dac724131aab0ba826e235459a1e02192bf4 Load also language information from tags files
@techee pushed 3 commits.
c1b00c214c898fa282022d3574887e7753003dba Add ctags 'readtags' library to allow us parse ctags files ae9b997f05b5ae76d0ea85d5805650da79224c6d Use the readtags library to parse ctags files ec52c3630c65ef000c69d44d5176130ee1b11146 Fix compilation when TM_DEBUG is defined
Just repushed with merge conflicts resolved and added handling for anonymous tags (which was in the meantime merged to master).
@techee pushed 3 commits.
8da9f0402891155297aae2fae0abc04a2e119cba Merge branch 'master' into ctags_readtags eba3576f2794823595eb210ff9f484bb7cc18a35 Add meson build support 8f4b1c33463885c567dd830c5c7f963078c0734f Support fileScope tag field
@techee pushed 2 commits.
8c358369ea52771ef0af93f8117ce03350e3b250 Revert "Support fileScope tag field" f49b19f3bfe61cf7ae27075f28ec5bd7c570a1ba Avoid going through unrecognized fields when we already have scope
In addition to this PR we should document that `-n --fields=fiklsZStE` are the recommended `ctags` command line arguments. In addition, I'd suggest that we recommend using ctags for tag file generation over Geany's tag generation because our tag file format depends on the mappings in
https://github.com/geany/geany/blob/master/src/tagmanager/tm_parser.c
and if we change the mapping there, the tag files generated by Geany may become invalid. Maybe we could also document that tag files generated on the command-line using `geany` are guaranteed to be only valid for the Geany release using which they were generated.
Maybe we could also document that tag files generated on the command-line using geany are guaranteed to be only valid for the Geany release using which they were generated.
In that case how are we going to handle [these](https://github.com/geany/geany/tree/master/data/tags), because that is saying they should be re-created every the build, and [thses](https://wiki.geany.org/tags/start) are also invalidated, or at least need a Geany version added to the Wiki.
I didn't mean they would always be invalidated, just that it could happen e.g. for a subset of tags. For some of the languages the mappings aren't very nice from what I have seen, we might want to introduce new mapping types to semantically better represent the feature of the given language and such a change could make the corresponding tag invalid (this is nothing new, it's how it always worked before).
We could do these things: 1. Store the ctags kind letter to the tagmanager-format tag files and use it instead of the mapped type if present (we could still fall back to the mapped type for legacy files). For this we could use some of the obsolete and unused entries in the tag files like `TA_TIME` here: https://github.com/geany/geany/blob/37d20a823fb1bca67cea57ef73aa9e64009d8138... Such updated tag files would be compatible across Geany releases. 2. Use the ctags file format for the tag files we ship with Geany (or for those, where it matters - the pipe-separated `pas` files and HTML entities without any kind specified are fine). 3. Or both.
I didn't mean they would always be invalidated
Perhaps invalidated was a poor choice of word and made it seem worse than it is.
IIUC what would happen now is that a symbol in an olde tags file will show as a different kind from what it would show as if the source file file was open in Geany, or the tags file re-generated. But it would still load, and will still show as the same kind it always did.
That does not seem to be an issue to me. Olde tags files are no worse, memory symbols and new tags files are an improvement, yay!
Store the ctags kind letter to the tagmanager-format tag files and use it instead of the mapped type if present Use the ctags file format for the tag files we ship with Geany
IIUC both of those mean relevant symbols from tags files from before the mapping change will change the kind they show. That may not be right, for example one of the recent parser updates split a kind into two IIRC (was it Ada? can't remember and too lazy to search) so now old file symbols using the letter that was split will all show as one of the halves. So both 1. and 2. will show something different for existing tags files. And if the parser removed a letter what happens, do we need to keep it in the mapping? Hopefully ctags will never reuse the same letter for a totally different kind, then we would have to complain to ctags?
So it seems with either 1. or 2. there is the same potential behaviour change.
My current evaluation is that having old tags file load the same way they always did, but different to new tags and open files is less likely to cause user issues. So doing nothing happens to be both the best solution and the easiest :-)
Or both.
Or neither for now.
But I agree that in the longer term it might be better to use ctags tags files directly, which this PR is a necessary step towards.
Now conflicts are fixed will try to test in the next few days.
Should I rebase this PR on top of master and squash some of the commits?
Now conflicts are fixed will try to test in the next few days.
IIRC it seemed to work with limited testing way back then, but seems I didn't post that, sorry. Didn't have anything complicated to test with.
By the way, I really think this PR should go to 2.0. @eht16 converted various tag-generating scripts to use the ctags file format and some things aren't parsed correctly now without this patch, see the end of https://github.com/geany/geany/pull/3512#issue-1740467282.
I wonder why PRs like this are open or so long and then rushed into the release. Not enough pinging?
@kugel- requested changes on this pull request.
- /* tag name */ - if (! (tab = strchr(p, '\t')) || p == tab) - return FALSE; - tag->name = g_strndup(p, (gsize)(tab - p)); - p = tab + 1; + if (entry.kind[0] && entry.kind[1]) + type = tm_parser_get_tag_type(tm_ctags_get_kind_from_name(entry.kind, lang), lang); // 'K' field
C-style comments, please : `/* 'K' field */` (more of that below)
@@ -154,7 +154,7 @@ gboolean tm_tag_is_anon(const TMTag *tag);
const char *tm_tag_type_name(const TMTag *tag);
-TMTagType tm_tag_name_type(const char* tag_name); +TMTagType tm_tag_name_type(const char* tag_name, TMParserType lang);
can't find the corresponding change in the C file-
@elextr commented on this pull request.
@@ -154,7 +154,7 @@ gboolean tm_tag_is_anon(const TMTag *tag);
const char *tm_tag_type_name(const TMTag *tag);
-TMTagType tm_tag_name_type(const char* tag_name); +TMTagType tm_tag_name_type(const char* tag_name, TMParserType lang);
No change, its fixing the .h to match the existing .c
@elextr commented on this pull request.
@@ -154,7 +154,7 @@ gboolean tm_tag_is_anon(const TMTag *tag);
const char *tm_tag_type_name(const TMTag *tag);
-TMTagType tm_tag_name_type(const char* tag_name); +TMTagType tm_tag_name_type(const char* tag_name, TMParserType lang);
Reference https://github.com/geany/geany/blob/987cc3f106bf1eb6c0c0667bf5f24582022180ae...
@techee commented on this pull request.
@@ -154,7 +154,7 @@ gboolean tm_tag_is_anon(const TMTag *tag);
const char *tm_tag_type_name(const TMTag *tag);
-TMTagType tm_tag_name_type(const char* tag_name); +TMTagType tm_tag_name_type(const char* tag_name, TMParserType lang);
Yes.
This change is quite independent from this PR, I just needed to define TM_DEBUG for debugging this PR so this is why it's here.
@techee pushed 2 commits.
14c3b8081c79da98f053eda3a2f61925eafa5933 Use C-style comments 5635539d55f069a06211854bc67f1db5d1679c69 End both loops when scope found
@techee commented on this pull request.
- /* tag name */ - if (! (tab = strchr(p, '\t')) || p == tab) - return FALSE; - tag->name = g_strndup(p, (gsize)(tab - p)); - p = tab + 1; + if (entry.kind[0] && entry.kind[1]) + type = tm_parser_get_tag_type(tm_ctags_get_kind_from_name(entry.kind, lang), lang); // 'K' field
Done, thanks.
@b4n commented on this pull request.
@@ -436,7 +443,6 @@ static TMTag *new_tag_from_tags_file(TMSourceFile *file, FILE *fp, TMParserType
result = init_tag_from_file_alt(tag, file, fp); break; case TM_FILE_FORMAT_CTAGS: - result = init_tag_from_file_ctags(tag, file, fp, mode);
might be worth a `g_warn_if_reached()`
fclose(fp); /* the readtags library opens the file by itself */
+ read_ctags_file(tags_file, mode, file_tags);
Doesn't the `# format=ctags` confuse this parser? I didn't try this yet, but it feels like it should: * prevent pseudo tags (`!_…` ones) from being recognized as such * get parsed as a normal entry
doesn't this happen?
Agreed this header it not necessary (and actually with supporting detection with some pseudo-tags probably not advisable), but it should either work, or we shouldn't pretend it still does.
{
- gchar buf[BUFSIZ]; - gchar *p, *tab; + tagEntry entry; + tagFile *f = tagsOpen(tags_file, NULL); + const gchar *lang_kinds = tm_ctags_get_lang_kinds(lang); + GPtrArray *unknown_fields = g_ptr_array_new_full(10, NULL);
any reason not to use `GArray` instead? OK it's a tad awkward as well, but less so than `GPtrArray` for storing integers I'd say. I don't have to draw you a picture, but:
```c GArray *array = g_array_sized_new(FALSE, FALSE, sizeof(guint), 10); g_array_append_val(array, i); guint i2 = g_array_index(array, guint, idx); ```
I'm not sure how robust our parser is against invalid input
I wrote most of it, it ought to be perfect :grin:
or updated ctags file format
In theory the format is perfectly well defined and stable (just adding new extension fields), so it should be fine™. But in practice uctags added support for escape sequences, which our parser doesn't understand, so it isn't.
so better use the upstream version of the official library to parse ctags files so we don't have to worry about this.
Yeah, it's a very large diff, but I guess using the canonical implementation is worth the extra copy.
@techee pushed 4 commits.
49386fb8c70a80019ef5cd75ba21ec86305759b2 Warn about using legacy # format=ctags and update documentation a2cf693790c238faf7ba32aa18b478b6eaa77dc6 Add a debug warning a4a7941d7a0a82a1ebc6edb1b90566e2d3851c05 Replace GPtrArray with GArray c5bfe6ace392f4f8c925de1fcb0e22efee94aed5 Allow "unknown" in addition to "typename" behind the typeref field
@techee commented on this pull request.
@@ -436,7 +443,6 @@ static TMTag *new_tag_from_tags_file(TMSourceFile *file, FILE *fp, TMParserType
result = init_tag_from_file_alt(tag, file, fp); break; case TM_FILE_FORMAT_CTAGS: - result = init_tag_from_file_ctags(tag, file, fp, mode);
Done.
@techee commented on this pull request.
fclose(fp); /* the readtags library opens the file by itself */
+ read_ctags_file(tags_file, mode, file_tags);
doesn't this happen?
You are absolutely right. When `format=ctags` is found in the file, I added ``` g_warning("# format=ctags directive is no longer supported; please remove it from %s", tags_file); ```
I also updated the documentation because it advised to use `# format=ctags` (hopefully nobody reads it ;-)
@techee commented on this pull request.
{
- gchar buf[BUFSIZ]; - gchar *p, *tab; + tagEntry entry; + tagFile *f = tagsOpen(tags_file, NULL); + const gchar *lang_kinds = tm_ctags_get_lang_kinds(lang); + GPtrArray *unknown_fields = g_ptr_array_new_full(10, NULL);
The fundamental reason was that I never used GArray ;-). I've updated the code with your suggestion.
I wrote most of it, it ought to be perfect 😁
Oh, I'm syncing it in the wrong direction - I should have updated ctags with your code :-).
I discovered one more problem - all parsers use `typeref:typename` but I just discovered after looking at Enrico's php tags file and at the php parser afterwards that php uses `typeref:unknown` for typenames for some reason. So I updated the code to allow `unknown` behind `typeref` too.
Maybe should I also grab the latest version of the libreadtags library for this PR? I noticed you also submitted some patch to it in the spring.
I wrote most of it, it ought to be perfect 😁
Oh, I'm syncing it in the wrong direction - I should have updated ctags with your code :-).
Meh, I also wrote some of that one, so either way works :grinning:
I discovered one more problem - all parsers use `typeref:typename` but I just discovered after looking at Enrico's php tags file and at the php parser afterwards that php uses `typeref:unknown` for typenames for some reason. So I updated the code to allow `unknown` behind `typeref` too.
Good catch. Maybe it'd be worth submitting an update to that parser to be more in line with the convention as well.
Maybe should I also grab the latest version of the libreadtags library for this PR? I noticed you also submitted some patch to it in the spring.
I didn't check the diff, but my latest changes there were not crucial, they fixed C stdlib usage, and some very theoretical issues handling some non-ASCII bytes.
Good catch. Maybe it'd be worth submitting an update to that parser to be more in line with the convention as well.
We'll still need the "unknown" check to support older ctags binaries unfortunately.
OK to rebase this branch on top of master so it can be more easily tested with the php and py tag files? I'd also squash the commits a bit.
We'll still need the "unknown" check to support older ctags binaries unfortunately.
Sure, but it'll still make it more coherent. Unless we fear it'd break compatibility at some level…
OK to rebase this branch on top of master so it can be more easily tested with the php and py tag files? I'd also squash the commits a bit.
Sure, fine with me.
We'll still need the "unknown" check to support older ctags binaries unfortunately.
At least we can easily change the PHP tags generation script when needed.
@techee pushed 3 commits.
e1ae976a7284d59f24b387825e967a2e6794a330 Add ctags 'readtags' library to allow us parse ctags files d364c30e7973ceaf387f8c64211d3980a462f90b Fix compilation when TM_DEBUG is defined d945009828e3c36b366a42448b009ea66f784090 Use the readtags library to parse ctags files
At least we can easily change the PHP tags generation script when needed.
But we still need to support user's tag files possibly generated by older ctags versions so it should stay there for some time even if we update the php parser.
@techee pushed 1 commit.
bb64384a6af2631ff6f4168118ff27e0dff1c4b5 Update geany.txt with ctags usage for generating tag files
@elextr requested changes on this pull request.
A couple of changes.
@@ -1785,6 +1786,25 @@ This works basically the same as on other platforms::
"c:\program files\geany\bin\geany" -g c:\mytags.php.tags c:\code\somefile.php
+Generating tags files using ctags +********************************* +Geany supports loading tag files generated using the ``ctags`` command-line +tool from the universal-ctags project (https://github.com/universal-ctags/ctags). +Even though Geany should work with any ctags file, it is recommended to use +certain fields to give Geany some additional information. The recommended fields +are ``EfiklsZSt``, so, for instance, to generate tags for all sources in the geany
delete "for instance" and comma after "directory"
+Generating tags files using ctags
+********************************* +Geany supports loading tag files generated using the ``ctags`` command-line +tool from the universal-ctags project (https://github.com/universal-ctags/ctags). +Even though Geany should work with any ctags file, it is recommended to use +certain fields to give Geany some additional information. The recommended fields +are ``EfiklsZSt``, so, for instance, to generate tags for all sources in the geany +directory, one can use:: + + ctags --fields=EfiklsZSt -o geany.c.tags -R geany + +Additional options may be given to the ``ctags`` tool, for instance, to restrict +the generated tags file to some languages only, use certain tag kinds, etc. + +Note that when the ``l`` field (specifying the programming language for every tag) +is enabled, the language of the tag is set based on this field instead of the
question, is it the tag or the symbol in Geany that gets the language specified?
@@ -1689,12 +1689,13 @@ Global tags files can have three different formats:
* Pipe-separated format * CTags format
-The first line of global tags files should be a comment, introduced -by ``#`` followed by a space and a string like ``format=pipe``, -``format=ctags`` or ``format=tagmanager`` respectively, these are +For the tagmanager or pipe-separated format, the first line of global tag files +should be a comment, introduced by ``#`` followed by a space and a string like
delete "a string like", its not "like" it is exactly one or other IIUC
case-sensitive. This helps Geany to read the file properly. If this
line is missing, Geany tries to auto-detect the used format but this -might fail. +might fail. Tag files using the CTags format should be left unmodified in the
"used format" above s/b "format used"
(I know its not your change, but might as well fix it)
@techee commented on this pull request.
@@ -1785,6 +1786,25 @@ This works basically the same as on other platforms::
"c:\program files\geany\bin\geany" -g c:\mytags.php.tags c:\code\somefile.php
+Generating tags files using ctags +********************************* +Geany supports loading tag files generated using the ``ctags`` command-line +tool from the universal-ctags project (https://github.com/universal-ctags/ctags). +Even though Geany should work with any ctags file, it is recommended to use +certain fields to give Geany some additional information. The recommended fields +are ``EfiklsZSt``, so, for instance, to generate tags for all sources in the geany
But there should still be comma after "so", right?
I will also renamed the "geany" directory to something like "my_project" to avoid possible confusion with the geany binary.
@techee commented on this pull request.
@@ -1689,12 +1689,13 @@ Global tags files can have three different formats:
* Pipe-separated format * CTags format
-The first line of global tags files should be a comment, introduced -by ``#`` followed by a space and a string like ``format=pipe``, -``format=ctags`` or ``format=tagmanager`` respectively, these are +For the tagmanager or pipe-separated format, the first line of global tag files +should be a comment, introduced by ``#`` followed by a space and a string like
Will do (also not mine ;-).
@techee commented on this pull request.
case-sensitive. This helps Geany to read the file properly. If this
line is missing, Geany tries to auto-detect the used format but this -might fail. +might fail. Tag files using the CTags format should be left unmodified in the
OK.
@elextr commented on this pull request.
@@ -1785,6 +1786,25 @@ This works basically the same as on other platforms::
"c:\program files\geany\bin\geany" -g c:\mytags.php.tags c:\code\somefile.php
+Generating tags files using ctags +********************************* +Geany supports loading tag files generated using the ``ctags`` command-line +tool from the universal-ctags project (https://github.com/universal-ctags/ctags). +Even though Geany should work with any ctags file, it is recommended to use +certain fields to give Geany some additional information. The recommended fields +are ``EfiklsZSt``, so, for instance, to generate tags for all sources in the geany
Could be either way, but my preference would be comma before so only.
@techee commented on this pull request.
+Generating tags files using ctags
+********************************* +Geany supports loading tag files generated using the ``ctags`` command-line +tool from the universal-ctags project (https://github.com/universal-ctags/ctags). +Even though Geany should work with any ctags file, it is recommended to use +certain fields to give Geany some additional information. The recommended fields +are ``EfiklsZSt``, so, for instance, to generate tags for all sources in the geany +directory, one can use:: + + ctags --fields=EfiklsZSt -o geany.c.tags -R geany + +Additional options may be given to the ``ctags`` tool, for instance, to restrict +the generated tags file to some languages only, use certain tag kinds, etc. + +Note that when the ``l`` field (specifying the programming language for every tag) +is enabled, the language of the tag is set based on this field instead of the
Oh, my response from yesterday disappeared somewhere. So once again - you mean whether to use the word "tag" or "symbol" here, right? I checked geany.txt and we only use "tags" in "tags file" but never talk about tags themselves so probably "symbol" is the correct one here. I've modified it to:
``` Note that when the ``l`` field (specifying the programming language) is enabled, the language of all symbols is set based on the value of this field instead of the language specified in the extension of the tags file. ```
Does it sound OK?
@elextr commented on this pull request.
+Generating tags files using ctags
+********************************* +Geany supports loading tag files generated using the ``ctags`` command-line +tool from the universal-ctags project (https://github.com/universal-ctags/ctags). +Even though Geany should work with any ctags file, it is recommended to use +certain fields to give Geany some additional information. The recommended fields +are ``EfiklsZSt``, so, for instance, to generate tags for all sources in the geany +directory, one can use:: + + ctags --fields=EfiklsZSt -o geany.c.tags -R geany + +Additional options may be given to the ``ctags`` tool, for instance, to restrict +the generated tags file to some languages only, use certain tag kinds, etc. + +Note that when the ``l`` field (specifying the programming language for every tag) +is enabled, the language of the tag is set based on this field instead of the
Yep fine.
@techee pushed 1 commit.
4ca132618802e4114c5ee08cbd8a7e55c8609e4c Improve wording of geany.txt
@techee commented on this pull request.
+Generating tags files using ctags
+********************************* +Geany supports loading tag files generated using the ``ctags`` command-line +tool from the universal-ctags project (https://github.com/universal-ctags/ctags). +Even though Geany should work with any ctags file, it is recommended to use +certain fields to give Geany some additional information. The recommended fields +are ``EfiklsZSt``, so, for instance, to generate tags for all sources in the geany +directory, one can use:: + + ctags --fields=EfiklsZSt -o geany.c.tags -R geany + +Additional options may be given to the ``ctags`` tool, for instance, to restrict +the generated tags file to some languages only, use certain tag kinds, etc. + +Note that when the ``l`` field (specifying the programming language for every tag) +is enabled, the language of the tag is set based on this field instead of the
Thanks, repushed with all the suggested changes.
@b4n requested changes on this pull request.
First pass only based on *code* review, no actual testing yet.
TMParserType lang = tm_ctags_get_named_lang(value);
+ if (lang >= 0) + tag->lang = lang;
```gcc ../../../src/tagmanager/tm_source_file.c: In function 'read_ctags_file': ../../../src/tagmanager/tm_source_file.c:394:46: warning: declaration of 'lang' shadows a parameter [-Wshadow] 394 | TMParserType lang = tm_ctags_get_named_lang(value); | ^~~~ ../../../src/tagmanager/tm_source_file.c:309:66: note: shadowed declaration is here 309 | static void read_ctags_file(const gchar *tags_file, TMParserType lang, GPtrArray *file_tags) | ~~~~~~~~~~~~~^~~~ ```
Maybe rename the local `tag_lang`?
```suggestion TMParserType tag_lang = tm_ctags_get_named_lang(value); if (tag_lang >= 0) tag->lang = tag_lang; ```
{
- if ((NULL == fgets(buf, BUFSIZ, fp)) || ('\0' == *buf)) - return FALSE; - } - while (strncmp(buf, "!_TAG_", 6) == 0); /* skip !_TAG_ lines */ + TMTagType type; + TMTag *tag; + guint i, idx;
```gcc ../../../src/tagmanager/tm_source_file.c:409:39: warning: declaration of 'i' shadows a previous local [-Wshadow] 409 | guint i = g_array_index(unknown_fields, guint, idx); | ^ ../../../src/tagmanager/tm_source_file.c:320:23: note: shadowed declaration is here 320 | guint i, idx; | ^ ```
Easy solution is to declare those in the `for` initialization, as we now accept this syntax.
```suggestion ```
- {
- p = tab + 2; - while (*p && *p != '\n' && *p != '\r') + tag = tm_tag_new(); + tag->refcount = 1; + tag->name = g_strdup(entry.name); + tag->type = type; + tag->lang = lang; + tag->local = entry.fileScope; /* 'f' field */ + tag->line = entry.address.lineNumber; /* 'n' field */ + tag->file = NULL; + + if (tm_parser_is_anon_name(lang, tag->name)) + tag->flags |= tm_tag_flag_anon_t; + + for (i = 0; i < entry.fields.count; i++)
```suggestion for (guint i = 0; i < entry.fields.count; i++) ```
}
- else if (0 == strcmp(key, "file")) /* static (local) tag */ - tag->local = TRUE; - else if (0 == strcmp(key, "signature")) /* arglist */ + else + g_array_append_val(unknown_fields, i); + } + + if (!tag->scope) + { + /* search for scope introduced by scope kind name only after going + * through all extension fields and having tag->lang updated when + * "language" field is present */ + for (idx = 0; !tag->scope && idx < unknown_fields->len; idx++)
```suggestion for (guint idx = 0; !tag->scope && idx < unknown_fields->len; idx++) ```
Or make this `i`, and make the local `idx`, which might be more idiomatic.
int j;
+ for (j = 0; lang_kinds[j]; j++)
…and while at it ```suggestion for (gint j = 0; lang_kinds[j]; j++) ```
{
- g_free(tag->arglist); - tag->arglist = g_strdup(value); + guint i = g_array_index(unknown_fields, guint, idx); + const gchar *key = entry.fields.list[i].key; + const gchar *value = entry.fields.list[i].value; + int j; + for (j = 0; lang_kinds[j]; j++) + { + gchar kind = lang_kinds[j];
```suggestion const gchar kind = lang_kinds[j]; ```
{
- g_free(tag->arglist); - tag->arglist = g_strdup(value); + guint i = g_array_index(unknown_fields, guint, idx);
```suggestion const guint i = g_array_index(unknown_fields, guint, idx); ```
{
- if (*end == ':' && ! value) + /* scope:class:A::B::C */ + gchar *val = strchr(value, ':');
```suggestion const gchar *val = strchr(value, ':'); ```
{
g_free(tag->inheritance); tag->inheritance = g_strdup(value); } - else if (0 == strcmp(key, "implementation")) /* implementation limit */ + else if (strcmp(key, "typeref") == 0) /* 't' field */ + { + /* typeref:typename:int */ + gchar *val = strchr(value, ':');
```suggestion const gchar *val = strchr(value, ':'); ```
@techee pushed 1 commit.
a088e452fbbef8bc08d0bc350265d98e45f048f0 Fix some compiler warnings
@elextr commented on this pull request.
{
- if ((NULL == fgets(buf, BUFSIZ, fp)) || ('\0' == *buf)) - return FALSE; - } - while (strncmp(buf, "!_TAG_", 6) == 0); /* skip !_TAG_ lines */ + TMTagType type; + TMTag *tag; + guint i, idx;
ooooh C99, better be careful, next it will be C11 ;-P
@techee pushed 1 commit.
43ee190b8ff0886a4b55313a7f75ba0da4c6083d Fix compiler warnings related to loop index variables
@techee commented on this pull request.
}
- else if (0 == strcmp(key, "file")) /* static (local) tag */ - tag->local = TRUE; - else if (0 == strcmp(key, "signature")) /* arglist */ + else + g_array_append_val(unknown_fields, i); + } + + if (!tag->scope) + { + /* search for scope introduced by scope kind name only after going + * through all extension fields and having tag->lang updated when + * "language" field is present */ + for (idx = 0; !tag->scope && idx < unknown_fields->len; idx++)
Or make this i, and make the local idx, which might be more idiomatic.
Yes, this is better, done this way.
By the way, how did you do these fancy committable "suggested change" thingies at github?
@elextr commented on this pull request.
}
- else if (0 == strcmp(key, "file")) /* static (local) tag */ - tag->local = TRUE; - else if (0 == strcmp(key, "signature")) /* arglist */ + else + g_array_append_val(unknown_fields, i); + } + + if (!tag->scope) + { + /* search for scope introduced by scope kind name only after going + * through all extension fields and having tag->lang updated when + * "language" field is present */ + for (idx = 0; !tag->scope && idx < unknown_fields->len; idx++)
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/re... see item 6
@techee pushed 1 commit.
bc49cd2750dacf0bb5f82b7f30d328df79f23e9e Document the recommended way of generating tags files
@b4n approved this pull request.
Apart the small doc changes, LGTM. Limited testing shows it works nicely, including mixed languages in a tags file. Older tags files I had laying around using either Pipe or Tagmanager format still seemed to work as usual. I didn't have any older ctags tags file with the now unsupported header, but adding it to a new one produces the warning yet seems to still work without too much problem.
+Geany supports loading tag files generated using the ``ctags`` command-line +tool from the universal-ctags project (https://github.com/universal-ctags/ctags). +Even though Geany should work with any ctags file, it is recommended to use +certain fields to give Geany some additional information. The recommended fields +are ``EfiklsZSt``, so to generate symbols for all sources in the my_project +directory one can use:: + + ctags -n --fields=EfiklsZSt -R -o my_project.c.tags my_project + +Additional options may be given to the ``ctags`` tool, for instance, to restrict +the generated tags file to some languages only, use certain tag kinds, etc. + +Note that when the ``l`` field (specifying the programming language) is enabled, +the language of all symbols is set based on the value of this field instead of +the language specified in the extension of the tags file.
```suggestion the language specified in the extension of the tags file. You however still have to name the file according to the same rules regardless of whether the language field is used. ```
or something like that, IIUC what you said somewhere else.
@b4n commented on this pull request.
{
- if ((NULL == fgets(buf, BUFSIZ, fp)) || ('\0' == *buf)) - return FALSE; - } - while (strncmp(buf, "!_TAG_", 6) == 0); /* skip !_TAG_ lines */ + TMTagType type; + TMTag *tag; + guint i, idx;
yeah, the future is knocking at our door!
@kugel- approved this pull request.
LGBI but I only understand a fraction of it anyway
@techee pushed 1 commit.
69ad323270615947ae6249c9eab2396c7301cf43 Add a remark about tag file naming when 'l' field is used
@b4n approved this pull request.
Apart the small doc changes, LGTM.
Committed now.
Alright, I'll wait for @elextr if he has some more comments to the documentation, then squash the commits a bit and merge the result afterwards.
@elextr approved this pull request.
LGBI, docs ok, I won't be home to be able to test anything until after release unfortunately
Great, so I've just re-pushed the squashed version in case someone wants to have a look at it. I'll merge it tomorrow (well, actually later today) but feel free to merge it earlier if you want.
Merged #3049 into master.
github-comments@lists.geany.org