qmk / qmk_firmware

Open-source keyboard firmware for Atmel AVR and Arm USB families
https://qmk.fm
GNU General Public License v2.0
18.09k stars 38.89k forks source link

YouCompleteMe support for auto completion #4855

Closed bbaserdem closed 2 years ago

bbaserdem commented 5 years ago

This is not an issue, but utilizing some other program to make editing easier; and if it can be enabled easily from the upstream.

Feature Request Type

Description

I am still a beginner when it comes to C. I use vim to edit files, with YouCompleteMe plugin for autocompletion.

YouCompleteMe requires a config file, or a compilation database for completion, but I am unsure how to get that working by myself.

What I don't understand is; can this be handled by compilation database (modification in make?) or do I need to specify myself on a config file.

yiancar commented 5 years ago

Hello there! The addon you linked to is an addon used directly on VIM, it has nothing to do with being added on a keyboard firmware, which is what QMK is:)

If you are looking for general programing the kind people of QMK discord might be able to help! TLDR; This is not an issue of QMK:)

tobbbles commented 5 years ago

Related

tobbbles commented 5 years ago

May I suggest using NeoVim w/ https://github.com/Shougo/neoinclude.vim

malob commented 5 years ago

@bbaserdem, I ran into a similar issue trying to get the ccls language server working with QMK. Unfortunately (as far as I can tell), the way QMK builds targets makes it hard to easily integrate with tooling for C/C++ projects.

I did manage to get it working eventually though. I wrote up the details here: https://www.reddit.com/r/olkb/comments/bhdzxe/has_anyone_got_a_c_language_server_working_with/elur31t/

@yiancar, I totally agree that supporting a particular tool or editor plugin isn't a QMK issue. However, it does seem that QMK's current build system is setup in such a way that it's hard to integrate it in the standard ways with C/C++ tooling in general.

In both @bbaserdem's case trying to get YouCompleteMe working, and my case trying to get ccls working, the core of the issue is that both tools require some configuration which tells them how the project/target is built. Both can either use, a compilation database usually in the form of a "compile_commands.json" file in the project root, or configuration provided in a custom format.

There are a few tools out there for generating compilation databases for make based C/C++ projects (e.g., bear and scan-build), but I wasn't able to get any of them to work with the QMK codebase (they just generated empty databases). Additionally, figuring out how to find the information I needed for ccls's custom configuration file, was pretty tough (for more details see the linked Reddit comment above).

Now all that said, I have very little experience working with C based projects, and I might just be missing something obvious ¯_(ツ)_/¯. But if I'm not, maybe it's worth seeing if some changes could be made to the build system so that it's more straight forward to use common C/C++ tooling while working on the QMK codebase, e.g., making it easy to generate a compilation database for a given target, and/or adding something to the QMK docs.

I'd be happy to help, but given that I barely understand how the current build system works, I don't think I'll get very far on my own.

malob commented 5 years ago

@drashna, any thoughts on the above?

drashna commented 5 years ago

Sorry.

NO, I don't really have an idea about this.

I know with VS Code, on Windows, at least, it wouldn't handle everything correctly unless I added the gcc (arm and avr) source folders to the pathing for VSCode. You may need to do the same thing.

malob commented 5 years ago

Thanks for the response 🙂.

Though I don't think that's the issue in my case. Everything works once I get the right configuration file setup.

stale[bot] commented 4 years ago

This issue has been automatically marked as resolved because it has not had activity in the last 90 days. It will be closed in the next 30 days unless it is tagged properly or other activity occurs.

bbaserdem commented 4 years ago

@malob that is very interesting that you managed a solution. I don't have the skillset to solve this at all.

That being said, I am going to copy paste your discussion here, as reddit is more volatile with comments that github. And I will probably want to set this up with ale at some point.

Malob

Yesterday I tried setting up ccls (a C/C++/ObjC language server) and ran into some issues getting it working with the QMK codebase. Most notably, the language server is having trouble with includes. For example, it reports the following errors, on the first to includes in my keymap.c file:

#include QMK_KEYBOARD_H // Error: expected FILENAME or <FILENAME> #include "muse.h". // Error: 'muse.h' file not found

I suspect this is because the language server doesn't know how to interpret QMK_KEYBOARD_H, and doesn't know where to find muse.h. I could probably solve this particular issue by hardcoding the relative paths to the relevant includes, but that seems like the wrong way to solve the problem. I assume there is some way to tell the language server which other directories it should look in to find includes, but so far I haven't been able to figure out how.

I've got a decent amount of experience using language servers with other languages, but this is my first time setting one up for a C codebase (and in general I have very little C experience aside from hacking on my Planck config).

Has anyone here gotten a language sever working with QMK? If so, I'd greatly appreciate any tips you might have.

(I'm using NeoVim with the LanguageClient-neovim plugin, and the project root is successfully being detected.)

Drashna

D:

That said, I'm guessing that you're using the ccls scripts to compile things, right?

If so, that's a problem. QMK Firmware's make scripts do a LOT behind the scenes, including setting paths for source (like muse.h), and generating QMK_KEYBOARD_H so it points to the correct file.

Ideally, you should integrate the stuff into QMK Firmware directly (maybe as a library), rather than an external project (which is what I think you're trying to do)

Malob

That said, I'm guessing that you're using the ccls scripts to compile things, right?

Maybe, depending what you mean. In order for the language server to provide diagnostics etc. it definitely has to understand how to compile the code, but I'm not using it to actually compile the code to generate the firmware for my keyboard. I still run make planck/rev6:malob in order to do that.

If so, that's a problem. QMK Firmware's make scripts do a LOT behind the scenes, including setting paths for source (like muse.h), and generating QMK_KEYBOARD_H so it points to the correct file.

Ideally, you should integrate the stuff into QMK Firmware directly (maybe as a library), rather than an external project (which is what I think you're trying to do)

I don't think adding something like a library makes sense here (though again I'm out of my depth in C land). Language servers are an editor agnostic way to provide of bunch of useful features, like autocompletion, goto definition, documentation on hover etc. Instead of these features needing to be implemented in each editor/ide, they can be implemented once by a language server using a standard protocol, and editors just need to know how to communicate with a language server over that standard protocol. (I expect you probably already knew that, but wanted to say it explicitly just to make sure we are on the same page.)

(Time passes)

So, after a bunch more research/experimenting I managed to find a solution. As you point out, the make scripts do a ton of stuff, which essentially tells the compiler how to build the target. In order for ccls to do it's job, it needs to know that stuff as well.

It looks like the standard way to support various tooling for C/C++ projects involves generating a "compilation database", which usually takes the form of a "compile_commands.json" file in the project root. The ccls wiki has a nice section on how to do this. Some projects make it easier than others. For example CMake based projects have it easy, since CMake has a built in way to generate the "compile_commands.json" file.

For make based projects like QMK, it's a little more complicated, you need to use tools like bear or scan-build. My rough understanding is that these tools wrap the build process and intercept calls to the compiler in order to generate the compilation database. Unfortunately these tools don't work on all make projects and QMK seems to be one of them. It may be that there is some way to make them work, but I haven't been able to figure it out. (If QMK is built using statically linked binaries rather than using a dynamic linker that could be the issue.)

Fortunately, ccls provides an alternative to using a compilation database. The language server will also look for a ".ccls" file in the project root, which specifies "compiler flags needed to properly index your code". Digging through the build products that QMK generates in the ".build" folder when I run make planck/rev6:malob, I found ".build/obj_planck_rev6_malob/cflags.txt" which looked like it contained the information needed for the ".ccls" file, though not in the correct format. Fortunately, it's pretty trivial to process the file into the correct format. This did the trick:

echo 'clang' > .ccls; cat .build/obj_planck_rev6_malob/cflags.txt | sed 's/ -/\ ` -/g' | sed 's/ //' | sed 's/ *$//' >> .ccls`

(Note that the newline is part of the command)

With that file in place, it works! Now when I'm hacking on QMK, I've got the full power of a language server :D

So in summary if you want to get a language server working with QMK, you need to,

  1. build the target your working on using the appropriate make command;
  2. find the relevant "cflags.txt" file in the ".build" folder; and
  3. reformat the contents of that file to ccls's liking, and place it in ".ccls" in the project root.

Given that language servers are getting pretty popular, I think it would be awesome if the build process for QMK made it a little easier to work with language servers. Maybe there's some way of getting bear/scan-build working with the code base, or maybe it could be done by adding some functionality to the make scripts, like a flag that when present would create the ".ccls" file automatically. Given that I have very little experience with C projects, this feels pretty daunting to me, but if you or someone else could point me in the right direction, I'd give it a shot.

okke-formsma commented 4 years ago

I had success generating a compile_commands.json file using scan-build's intercept-build command:

pip install scan-build
make clean
intercept-build make kyria:default

Combined with vs code's cmake tools plugin this gives me now good highlighting of enabled/disabled ifdefs.

https://github.com/rizsotto/scan-build

malob commented 4 years ago

@okke-formsma, hmmm interesting, I just tried that both for crkbd:default and kyria:default and I'm getting a compile_commands.json file that only contains [] :(

okke-formsma commented 4 years ago

Did you make clean first? Also I'm on Ubuntu, maybe that makes a difference?

shieldsd commented 4 years ago

I've just tried this and it generates a valid compile_commands.json file for me. I'm using the vim-lsp completer with clangd.

malob commented 4 years ago

I'm on macOS so that might be the issue. My other main hypothesis is that this is Nix related. I'm using nix-shell (along with the shell.nix file in the repo) to setup an environment where the toolchain required for QMK is available. Would be great if someone using either macOS or Nix could try this out, and report back about whether they had any success.

shieldsd commented 4 years ago

I'll try this out on macOS when I get some time.

xton commented 4 years ago

Just submitted https://github.com/qmk/qmk_firmware/pull/8916 which adds a simpler way of creating compile_commands.json. No build tool interception necessary; It just parses make -n output.

github-actions[bot] commented 2 years ago

This issue has been automatically marked as stale because it has not had activity in the last 90 days. It will be closed in the next 30 days unless it is tagged properly or other activity occurs. For maintainers: Please label with bug, in progress, on hold, discussion or to do to prevent the issue from being re-flagged.

tzarc commented 2 years ago

Closing due to inactivity.