- Notifications
You must be signed in to change notification settings - Fork24
agda/cornelis
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
I'll ask to stand up
With a show about a rooster,
Which was old and worn out,
Impotent and weathered.
The chickens complained and whined
Because he did not satisfy them.
cornelis
isagda-mode, but for neovim. It's written in Haskell, which meansit's maintainable and significantly less likely to bit-rot like anyvimscript/lua implementations.
It supports highlighting, goal listing, type-context, refinement, auto, solving,case splitting, go-to definition, normalization, and helper functions. These areexposed via vim commands. Most commands have an equivalent inagda-mode.
Vim command | Description | Equivalent agda-mode keybinding |
---|---|---|
:CornelisLoad | Load and type-check buffer | C-cC-l |
:CornelisGoals | Show all goals | C-cC-? |
:CornelisRestart | Kill and restart theagda process | C-cC-xC-r |
:CornelisAbort | Abort running command | C-cC-xC-a |
:CornelisSolve <RW> | Solve constraints | C-cC-s |
:CornelisGoToDefinition | Jump to definition of name at cursor | M-. or middle mouse button |
:CornelisPrevGoal | Jump to previous goal | C-cC-b |
:CornelisNextGoal | Jump to next goal | C-cC-f |
:CornelisQuestionToMeta | Expand? -holes to{! !} | (none) |
:CornelisInc | Like<C-A> but also targets sub- and superscripts | (none) |
:CornelisDec | Like<C-X> but also targets sub- and superscripts | (none) |
:CornelisCloseInfoWindows | Close (all) info windows cornelis has opened | (none) |
These commands can be used in context of a hole:
Vim command | Description | Equivalent agda-mode keybinding |
---|---|---|
:CornelisGive | Fill goal with hole contents | C-cC-SPC |
:CornelisRefine | Refine goal | C-cC-r |
:CornelisElaborate <RW> | Fill goal with normalized hole contents | C-cC-m |
:CornelisAuto | Automatic proof search | C-cC-a |
:CornelisMakeCase | Case split | C-cC-c |
:CornelisTypeContext <RW> | Show goal type and context | C-cC-, |
:CornelisTypeInfer <RW> | Show inferred type of hole contents | C-cC-d |
:CornelisTypeContextInfer <RW> | Show goal type, context, and inferred type of hole contents | C-cC-. |
:CornelisNormalize <CM> | Compute normal of hole contents | C-cC-n |
:CornelisWhyInScope | Show why given name is in scope | C-cC-w |
:CornelisHelperFunc <RW> | Copy inferred type to register" | C-cC-h |
Commands with an<RW>
argument take an optional normalization mode argument,one ofAsIs
,Instantiated
,HeadNormal
,Simplified
orNormalised
. Whenomitted, defaults toNormalised
.This default may be specified in vimrc asg:cornelis_rewrite_mode
.
Commands with a<CM>
argument take an optional compute mode argument:
<CM> | Description | Equivalent agda-mode prefix |
---|---|---|
DefaultCompute | default, used if<CM> is omitted | no prefix, default |
IgnoreAbstract | compute normal form, ignoringabstract s | C-u |
UseShowInstance | compute normal form of print usingshow instance | C-uC-u |
HeadCompute | compute weak-head normal form | C-uC-uC-u |
If Agda is stuck executing a command (e.g. if normalization takes too long),abort the command with:CornelisAbort
.
If you need to restart the plugin (eg if Agda is stuck in a loop), you canrestart everything via:CornelisRestart
.
There is reasonably good support for agda-input via your<LocalLeader>
ininsert mode. Seeagda-input.vimfor available bindings.
If you'd like to use a prefix other than your<LocalLeader>
, add the followingto your.vimrc
:
letg:cornelis_agda_prefix="<Tab>"" Replace with your desired prefix
If you'd like an interactive prompt for choosing unicode characters,additionally installvim-which-key
:
Plug'liuchengxu/vim-which-key'
and map a call tocornelis#prompt_input()
in insert mode:
inoremap<localleader><C-O>:callcornelis#prompt_input()<CR>
If you don't want any of the default bindings, add the following to your.vimrc
:
letg:cornelis_no_agda_input=1
Custom bindings can be added by calling thecornelis#bind_input
function in.vimrc
. For example:
callcornelis#bind_input("nat","ℕ")
will add<LocalLeader>nat
as an input remapping forℕ
.
If you'd prefer to manage agda-input entirely on your own (perhaps in a snippetsystem), you can set the following:
function!MyCustomHook(key,character)" do somethingendfunctionletg:cornelis_bind_input_hook="MyCustomHook"
You can invokecornelis#standard_bind_input
with the same arguments if you'dlike to run your hook in addition to the standard one.
Use theiz
/az
text objects to operate on text between⟨
and⟩
. Somewhatsurprisingly for i/a text objects,iz
targets thespaces between thesebrackets, andaz
targets the spaces. Neither textobj targets the bracketsthemselves.
Alsoii
/ai
will operate on⦃
and⦄
, but in the way you'd expecttext objects to behave.
ih
/ah
will operate on{!
and!}
.
Make sure you havestack
on your PATH!
Forvim-plug:
Plug'kana/vim-textobj-user'Plug'neovimhaskell/nvim-hs.vim'Plug'isovector/cornelis', {'do':'stack build','tag':'*' }
forlazy.nvim:
{'isovector/cornelis',name='cornelis',ft='agda',build='stack install',dependencies= {'neovimhaskell/nvim-hs.vim','kana/vim-textobj-user'},version='*',}
If you are having issues, try using a tag which matches your agda major version(e.g. for Agdav2.7.0.1
use cornelisv2.7.*
). If there is no matchingversion that is working for a new version of agda, please create an issue.
You can install both the vim plugin and the cornelis binary using nix flakes!You can access the binary ascornelis.packages.<my-system>.cornelis
and thevim plugin ascornelis.packages.<my-system>.cornelis-vim
. Below is a sampleconfiguration to help you understand where everything plugs in.
Nix details
# flake.nix{description="my-config";inputs={nixpkgs.url="github:nixos/nixpkgs/nixpkgs-unstable";home-manager={url="github:nix-community/home-manager";inputs.nixpkgs.follows="nixpkgs";};cornelis.url="github:isovector/cornelis";cornelis.inputs.nixpkgs.follows="nixpkgs";};outputs={home-manager,nixpkgs,cornelis, ...}:{nixosConfigurations={bellerophon=nixpkgs.lib.nixosSystem{system="x86_64-linux";modules=[home-manager.nixosModules.home-manager{nixpkgs.overlays=[cornelis.overlays.cornelis];home-manager.useGlobalPkgs=true;home-manager.useUserPackages=true;home-manager.users.my-home=import./my-home.nix;}];};};};}# my-home.nix{pkgs, ...}:{home.packages=[pkgs.agda];programs.neovim={enable=true;extraConfig=builtins.readFile./init.vim;plugins=[{# plugin packages in required Vim plugin dependenciesplugin=pkgs.vimPlugins.cornelis;config="let g:cornelis_use_global_binary = 1";}];extraPackages=[pkgs.cornelis];};}
Make sure you enable the global binary option in your vim config. Since/nix/store
is immutable cornelis will fail whennvim-hs
tries to run stack,which it will do if the global binary option isn't enabled.
Vimscript:
letg:cornelis_use_global_binary=1
Lua:
vim.g.cornelis_use_global_binary=1
Once you havecornelis
installed, you'll probably want to add some keybindingsfor it! This is enough to get you started:
auBufRead,BufNewFile*.agdacallAgdaFiletype()auQuitPre*.agda :CornelisCloseInfoWindowsfunction!AgdaFiletype()nnoremap<buffer><leader>l:CornelisLoad<CR>nnoremap<buffer><leader>r:CornelisRefine<CR>nnoremap<buffer><leader>d:CornelisMakeCase<CR>nnoremap<buffer><leader>,:CornelisTypeContext<CR>nnoremap<buffer><leader>.:CornelisTypeContextInfer<CR>nnoremap<buffer><leader>n:CornelisSolve<CR>nnoremap<buffer><leader>a:CornelisAuto<CR>nnoremap<buffer>gd:CornelisGoToDefinition<CR>nnoremap<buffer>[/:CornelisPrevGoal<CR>nnoremap<buffer>]/:CornelisNextGoal<CR>nnoremap<buffer><C-A>:CornelisInc<CR>nnoremap<buffer><C-X>:CornelisDec<CR>endfunction
Feeling spicy? Automatically runCornelisLoad
every time you save the file.
auBufWritePost*.agdaexecute"normal! :CornelisLoad\<CR>"
If you'd like to automatically load files when you open them too, try this:
function!CornelisLoadWrapper()ifexists(":CornelisLoad")==#2 CornelisLoadendifendfunctionauBufReadPre*.agdacallCornelisLoadWrapper()auBufReadPre*.lagda*callCornelisLoadWrapper()
This won't work on the first Agda file you open due to a bug, but it willsuccessfully load subsequent files.
The max height and width of the info window can be set via:
letg:cornelis_max_size=30
and
letg:cornelis_max_width=40
If you'd prefer your info window to appear somewhere else, you can setg:cornelis_split_location
(previouslyg:cornelis_split_direction
), e.g.
letg:cornelis_split_location='vertical'
The following configuration options are available:
horizontal
: The default, opens in a horizontal split respectingsplitbelow
.vertical
: Opens in a vertical split respectingsplitright
.top
: Opens at the top of the window.bottom
: Opens at the bottom of the window.left
: Opens at the left of the window.right
: Opens at the right of the window.
Set default rewrite mode to use in commands which take an optionalnormalization mode argument
letg:cornelis_rewrite_mode='HeadNormal'
The following configuration options are available:
AsIs
Instantiated
HeadNormal
Simplified
Normalised
If you're interested in automatically aligning your reasoning justifications,also install the following plugin:
Plug'junegunn/vim-easy-align'
and add the following configuration for it:
vmap<leader><space><Plug>(EasyAlign)letg:easy_align_delimiters= {\'r': {'pattern':'[≤≡≈∎]','left_margin':2,'right_margin':0 },\}
You can now align justifications by visually selecting the proof, and thentyping<leader><space>r
.
Syntax highlighting is controlled by syntax groups namedCornelis*
,defined insyntax/agda.vim
.These groups are linked to default highlighting groups(:h group-name
),and can be customized by overriding them in user configuration.
" Highlight holes with a yellow undercurl/underline:highlight CornelisHole ctermfg=yellow ctermbg=NONE cterm=undercurl" Highlight "generalizables" (declarations in `variable` blocks) like constants:highlightlinkCornelisGeneralizableConstant
I'm a noob at Agda, and I don't know what I don't know. If this plugin doesn'thave some necessary feature for you to get work done, please file a bug,including both what's missing, and how you use it in your workflow. I'd love tolearn how to use Agda better! I can move quickly on feature requests.
If you'd like to get involved, feel free to tackle an issue on the tracker andsend a PR. I'd love to have you on board!
Cornelis spins up a newBufferStuff
for each Agda buffer it encounters.BufferStuff
contains a handle to a uniqueagda
instance, which can be usedto send commands. It also tracks things like the information window buffer,in-scope goals, and whatever the lastDisplayInfo
response fromagda
was.
For eachBufferStuff
, we also spin up a new thread, blocking on responsesfromagda
. These responses all get redirected to a global worker thread, whichis responsible for dispatching on each command. Commands are typesafe, parsedfrom JSON, and associated with the buffer they came from.
About
agda-mode for neovim
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.