From ff2102be96ff3477e1537b98e192a24ba8ca7b9b Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Wed, 27 Sep 2023 16:06:12 +0300 Subject: [PATCH] docs/hacking: add contributing guidelines --- docs/default.nix | 21 ++- docs/man-configuration.xml | 5 +- docs/manual.xml | 10 +- docs/manual/hacking.adoc | 370 +++++++++++++++++++++++++++++++++++++ 4 files changed, 398 insertions(+), 8 deletions(-) create mode 100644 docs/manual/hacking.adoc diff --git a/docs/default.nix b/docs/default.nix index 683dc9c..211bf38 100644 --- a/docs/default.nix +++ b/docs/default.nix @@ -3,24 +3,41 @@ lib ? import ../lib/stdlib-extended.nix pkgs.lib, nmdSrc, }: let - nmd = import nmdSrc {inherit lib pkgs;}; + nmd = import nmdSrc { + inherit lib; + # The DocBook output of `nixos-render-docs` doesn't have the change + # `nmd` uses to work around the broken stylesheets in + # `docbook-xsl-ns`, so we restore the patched version here. + pkgs = + pkgs + // { + docbook-xsl-ns = + pkgs.docbook-xsl-ns.override {withManOptDedupPatch = true;}; + }; + }; + + # Make sure the used package is scrubbed to avoid actually + # instantiating derivations. scrubbedPkgsModule = { imports = [ { _module.args = { pkgs = lib.mkForce (nmd.scrubDerivations "pkgs" pkgs); + pkgs_i686 = lib.mkForce {}; }; } ]; }; + dontCheckDefinitions = {_module.check = false;}; + nvimModuleDocs = nmd.buildModulesDocs { modules = import ../modules/modules.nix { inherit pkgs lib; check = false; } - ++ [scrubbedPkgsModule]; + ++ [scrubbedPkgsModule dontCheckDefinitions]; moduleRootPaths = [./..]; mkModuleUrl = path: "https://github.com/notashelf/neovim-flake/blob/main/${path}#blob-path"; channelName = "neovim-flake"; diff --git a/docs/man-configuration.xml b/docs/man-configuration.xml index 498c0a0..01e7253 100644 --- a/docs/man-configuration.xml +++ b/docs/man-configuration.xml @@ -14,7 +14,8 @@ Description - Custom configuration is done with the neovim-flake.lib.neovimConfiguration function. It takes in the configuration as a module. + Custom configuration is done with the neovim-flake.lib.neovimConfiguration if home-manager module is not in use. + It takes in the configuration as a module. neovim-flake.lib.neovimConfiguration { inherit pkgs; @@ -31,6 +32,8 @@ neovim = "The built neovim package"; } + In case of the home-manager module, all options will be available under programs.neovim-flake once the module has + been imported from the flake inputs. Options diff --git a/docs/manual.xml b/docs/manual.xml index b16baa1..0464330 100644 --- a/docs/manual.xml +++ b/docs/manual.xml @@ -9,11 +9,10 @@ Preface - If your problem is caused by a bug in neovim-flake then it should be reported on the - neovim-flake issue tracker. - Alongside bug reports, feature requests are also welcome over - neovim-flake pull requests. - + If you believe your problem is caused by a bug in neovim-flake then please consider reporting it over + the neovim-flake issue tracker. + Bugfixes, feature additions and upstream changes are welcome over + the neovim-flake pull requests tab. @@ -23,6 +22,7 @@ + Configuration Options diff --git a/docs/manual/hacking.adoc b/docs/manual/hacking.adoc new file mode 100644 index 0000000..d9b5331 --- /dev/null +++ b/docs/manual/hacking.adoc @@ -0,0 +1,370 @@ +[[ch-hacking]] +== Hacking neovim-flake + +<<<<<<< HEAD +neovim-flake is designed for developers as much as it is for the end user. I would like any potential contributor +to be able to propagate their desired changes into the repository without the extra effort. As such, below are guides +(and guidelines) to streamline the contribution process and ensure that your valuable input seamlessly integrates +||||||| parent of c609a56 (among us) +neovim-flake is designed for developers as much as it is for the end user. I would like any potential contributor to +be able to propagate their desired changes into the repository without the extra effort. As such, below are guides +(and guidelines) to streamline the contribution process and ensure that your valuable input seamlessly integrates +======= +neovim-flake is designed for developers as much as it is for the end user. I would like any potential contributor to +be able to propagate their desired changes into the repository without the extra effort. As such, below are guides +(and guidelines) to streamline the contribution process and ensure that your valuable input seamlessly integrates +>>>>>>> c609a56 (among us) +into neovim-flake's development without leaving question marks in your head. + +:open-issues: https://github.com/notashelf/neovim-flake/issues +:new-issue: https://github.com/notashelf/neovim-flake/issues/new +:seven-rules: https://cbea.ms/git-commit/#seven-rules +:example-commit-message: https://github.com/nix-community/home-manager/commit/69f8e47e9e74c8d3d060ca22e18246b7f7d988ef + +This section is mainly directed towards those who wish to contribute code into neovim-flake. If you wish to instead +report a bug or discuss a potential feature implementation, first look among the already {open-issues}[open issues] and +if no matching issue exists you may open a {new-issue}[new issue] and describe your problem/request. While creating an +issue, please try to include as much information as you can, ideally also include relevant context in which an issue +occurs or a feature should be implemented. + +[[sec-contrib-getting-started]] +==== Getting started + +You naturally would like to start by forking the repository. If you are new to git, have a look at GitHub's +{fork-a-repo}[Fork a repo guide] for instructions on how you can do this. Once you have a fork of neovim-flake +you should create a branch starting at the most recent `main` branch. +Give your branch a reasonably descriptive name, suffixed by its type - i.e `feature/debugger` or `fix/pesky-bug`. + +Implement your changes and commit them to the newly created branch and when you are happy with the result and positive that it +fulfills <>. Once you are confident everything is in order, push the branch to GitHub and +{create-a-pull-request}[create a pull request], following the template that you will be prompted to fill. + +[[sec-guidelines]] +=== Guidelines +:assertions: https://nixos.org/manual/nixos/stable/index.html#sec-assertions +:discussions-tab: https://github.com/NotAShelf/neovim-flake/discussions + +If your contribution tightly follows the guidelines, then there is a good chance it will be merged without too much +trouble. Some of the guidelines will be strictly enforced, others will remain as gentle nudges towards the correct +direction. As we have no automated system enforcing those guidelines, please try to double check your changes before +making your pull request in order to avoid "faulty" code slipping by. + +If you are uncertain how these rules affect the change you would like to make then feel free to start a +discussion in the {discussions-tab}[discussions tab] ideally (but not necessarily) before you start developing. + +[[sec-documentation]] +==== Add adequate documentation +:nixpkgs-markdown: https://nixos.org/manual/nixpkgs/unstable/#sec-contributing-markup +:docbook: https://tdg.docbook.org/ +:asciidoc: https://asciidoc.org/ + +Most, if not all, changes warrant changes to the documentation. Module options should be documented with +{nixpkgs-markdown}[Nixpkgs-flavoured Markdown], albeit with exceptions. +neovim-flake is itself documented using a combination of {docbook}[DocBook] and {asciidoc}[AsciiDoc] conventions. + +The HTML version of this manual containing both the module option descriptions and the documentation of neovim-flake +(such as this page) can be generated and opened by typing the following in a shell within a clone of the +neovim-flake Git repository: + +[source,console] +---- +$ nix build .#docs-html +$ xdg-open ./result/share/doc/neovim-flake/index.html +---- + +[[sec-guidelines-code-style]] +==== Format your code + +Make sure your code is formatted as described in <>. To maintain consistency throughout the project +you are encouraged to browse through existing code and adopt its style also in new code. + +[[sec-guidelines-commit-message-style]] +==== Format your commit messages + +Similar to <> we encourage a consistent commit message format as described +in <>. + +[[sec-commit-style]] +==== Commits + +The commits in your pull request should be reasonably self-contained. Which means each and every commit in +a pull request should make sense both on its own and in general context. That is, a second commit should not resolve +an issue that is introduced in an earlier commit. In particular, you will be asked to amend any commit that +introduces syntax errors or similar problems even if they are fixed in a later commit. + +The commit messages should follow the {seven-rules}[seven rules], except for "Capitalize the subject line". +We also ask you to include the affected code component or module in the first line. +A commit message ideally, but not necessarily, follow the given template from home-manager's own documentation + +---- +{component}: {description} + +{long description} +---- + +where `{component}` refers to the code component (or module) your change affects, `{description}` is a very brief +description of your change, and `{long description}` is an optional clarifying description. As a rare exception, if +there is no clear component, or your change affects many components, then the `{component}` part is optional. +See <> for a commit message that fulfills these requirements. + +[[ex-commit-message]] +.Compliant commit message +=============================================================================== +The commit {example-commit-message}[69f8e47e9e74c8d3d060ca22e18246b7f7d988ef] contains the commit message + +---- +starship: allow running in Emacs if vterm is used + +The vterm buffer is backed by libvterm and can handle Starship prompts +without issues. +---- +=============================================================================== + +Long description can be ommitted if the change is too simple to warrant it. A minor fix in spelling or a formatting +change does not warrant long description, however, a module addition or removal does as you would like to provide the +relevant context for your changes. + +Finally, when adding a new module, say `modules/foo.nix`, we use the fixed commit format `foo: add module`. +You can, of course, still include a long description if you wish. + +In case of nested modules, i.e `modules/languages/java.nix` you are recommended to contain the parent as well - for +example `languages/java: some major change`. + + +[[sec-code-style]] +==== Code Style +:alejandra: https://github.com/kamadorueda/alejandra + +**Treewide** +Keep lines at a reasonable width, ideally 80 characters or less. This also applies to string literals and module +descriptions and documentation. + +**Nix** +neovim-flake is formatted by the {alejandra}[alejandra] tool and the formatting is checked in the pull +request and push workflows. Run the `nix fmt` command inside the project repository before submitting your +pull request. + +While Alejandra is mostly opinionated on how code looks after formatting, certain changes are done at the +user's discretion based on how the original code was structured. + +Please use one line code for attribute sets that contain only one subset. +For example: + +[source,nix] +---- +# parent modules should always be unfolded +module = { + value = mkEnableOption "some description" // { default = true; }; # merges can be done inline where possible + + # same as parent modules, unfold submodules + subModule = { + # this is an option that contains more than one nested value + someOtherValue = mkOption { + type = lib.types.bool; + description = "Some other description" + default = true; + }; + }; +} +---- + +If you move a line down after the merge operator, Alejandra will automatically unfold the whole merged attrset +for you, which we **do not** want. + +[source,nix] +---- +module = { + key = mkEnableOption "some description" // { + default = true; # we want this to be inline + }; + # ... +} +---- + +For lists, it is mostly up to your own discretion how you want to format them, but please try to unfold lists if +they contain multiple items and especially if they are to include comments. + +[source,nix] +---- +# this is ok +acceptableList = [ + item1 # comment + item2 + item3 # some other comment + item4 +]; + +# this is not ok +listToBeAvoided = [item1 item2 /* comment */ item3 item4]; + +# this is ok +singleItemList = [item1]; +---- + +[[sec-keybinds]] +=== Keybinds +As of 0.4, there exists an API for writing your own keybinds and a couple of useful utility functions are available in +the https://github.com/NotAShelf/neovim-flake/tree/main/lib[extended standard library]. The following section contains +a general overview to how you may utilize said functions. + +[[sec-custom-key-mappings]] +=== Custom Key Mappings Support for a Plugin + +:maps: https://notashelf.github.io/neovim-flake/options.html#opt-vim.maps.command._name_.action + +To set a mapping, you should define it in `vim.maps.<>`. +The available modes are: + +* normal +* insert +* select +* visual +* terminal +* normalVisualOp +* visualOnly +* operator +* insertCommand +* lang +* command + +An example, simple keybinding, can look like this: + +[source,nix] +---- +{ + vim.maps.normal = { + "wq" = { + action = ":wq"; + silent = true; + desc = "Save file and quit"; + }; + }; +} +---- + +There are many settings available in the options. Please refer to the {maps}[documentation] to see a list of them. + +`neovim-flake` provides a list of helper commands, so that you don't have to write the mapping attribute sets every +time: + +* `mkBinding = key: action: desc:` - makes a basic binding, with `silent` set to true. +* `mkExprBinding = key: action: desc:` - makes an expression binding, with `lua`, `silent`, and `expr` set to true. +* `mkLuaBinding = key: action: desc:` - makes an expression binding, with `lua`, and `silent` set to true. + +Note that the Lua in these bindings is actual Lua, not pasted into a `:lua` command. +Therefore, you either pass in a function like `require('someplugin').some_function`, without actually calling it, +or you define your own function, like `function() require('someplugin').some_function() end`. + +Additionally, to not have to repeat the descriptions, there's another utility function with its own set of functions: + +[source,nix] +---- +# Utility function that takes two attrsets: +# { someKey = "some_value" } and +# { someKey = { description = "Some Description"; }; } +# and merges them into +# { someKey = { value = "some_value"; description = "Some Description"; }; } + +addDescriptionsToMappings = actualMappings: mappingDefinitions: +---- + +This function can be used in combination with the same `mkBinding` functions as above, except they only take two +arguments - `binding` and `action`, and have different names: + +* `mkSetBinding = binding: action:` - makes a basic binding, with `silent` set to true. +* `mkSetExprBinding = binding: action:` - makes an expression binding, with `lua`, `silent`, and `expr` set to true. +* `mkSetLuaBinding = binding: action:` - makes an expression binding, with `lua`, and `silent` set to true. + +You can read the source code of some modules to see them in action, but their usage should look something like this: + +[source,nix] +---- +# plugindefinition.nix +{lib, ...}: +with lib; { + options.vim.plugin = { + enable = mkEnableOption "Enable plugin"; + + # Mappings should always be inside an attrset called mappings + mappings = { + # mkMappingOption is a helper function from lib, + # that takes a description (which will also appear in which-key), + # and a default mapping (which can be null) + toggleCurrentLine = mkMappingOption "Toggle current line comment" "gcc"; + toggleCurrentBlock = mkMappingOption "Toggle current block comment" "gbc"; + + toggleOpLeaderLine = mkMappingOption "Toggle line comment" "gc"; + toggleOpLeaderBlock = mkMappingOption "Toggle block comment" "gb"; + + toggleSelectedLine = mkMappingOption "Toggle selected comment" "gc"; + toggleSelectedBlock = mkMappingOption "Toggle selected block" "gb"; + }; + }; +} +---- + +[source,nix] +---- +# config.nix +{ + pkgs, + config, + lib, + ... +}: +with lib; +with builtins; let + cfg = config.vim.plugin; + self = import ./plugindefinition.nix {inherit lib;}; + mappingDefinitions = self.options.vim.plugin; + + # addDescriptionsToMappings is a helper function from lib, + # that merges mapping values and their descriptions + # into one nice attribute set + mappings = addDescriptionsToMappings cfg.mappings mappingDefinitions; +in { + config = mkIf (cfg.enable) { + # ... + + vim.maps.normal = mkMerge [ + # mkSetBinding is another helper function from lib, + # that actually adds the mapping with a description. + (mkSetBinding mappings.findFiles " Telescope find_files") + (mkSetBinding mappings.liveGrep " Telescope live_grep") + (mkSetBinding mappings.buffers " Telescope buffers") + (mkSetBinding mappings.helpTags " Telescope help_tags") + (mkSetBinding mappings.open " Telescope") + + (mkSetBinding mappings.gitCommits " Telescope git_commits") + (mkSetBinding mappings.gitBufferCommits " Telescope git_bcommits") + (mkSetBinding mappings.gitBranches " Telescope git_branches") + (mkSetBinding mappings.gitStatus " Telescope git_status") + (mkSetBinding mappings.gitStash " Telescope git_stash") + + (mkIf config.vim.lsp.enable (mkMerge [ + (mkSetBinding mappings.lspDocumentSymbols " Telescope lsp_document_symbols") + (mkSetBinding mappings.lspWorkspaceSymbols " Telescope lsp_workspace_symbols") + + (mkSetBinding mappings.lspReferences " Telescope lsp_references") + (mkSetBinding mappings.lspImplementations " Telescope lsp_implementations") + (mkSetBinding mappings.lspDefinitions " Telescope lsp_definitions") + (mkSetBinding mappings.lspTypeDefinitions " Telescope lsp_type_definitions") + (mkSetBinding mappings.diagnostics " Telescope diagnostics") + ])) + + ( + mkIf config.vim.treesitter.enable + (mkSetBinding mappings.treesitter " Telescope treesitter") + ) + ]; + + # ... + }; +} +---- + +[NOTE] +==== +If you have come across a plugin that has an API that doesn't seem to easily allow custom keybindings, +don't be scared to implement a draft PR. We'll help you get it done. +====