Refresh generated neovim config
This commit is contained in:
@ -1,49 +0,0 @@
|
||||
---@diagnostic disable: deprecated, duplicate-doc-field, duplicate-doc-alias
|
||||
---@mod haskell-tools.compat Functions for backward compatibility with older Neovim versions
|
||||
---@brief [[
|
||||
|
||||
---WARNING: This is not part of the public API.
|
||||
---Breaking changes to this module will not be reflected in the semantic versioning of this plugin.
|
||||
|
||||
---@brief ]]
|
||||
|
||||
local compat = {}
|
||||
|
||||
compat.joinpath = vim.fs.joinpath or function(...)
|
||||
return (table.concat({ ... }, '/'):gsub('//+', '/'))
|
||||
end
|
||||
|
||||
compat.get_clients = vim.lsp.get_clients or vim.lsp.get_active_clients
|
||||
|
||||
compat.uv = vim.uv or vim.loop
|
||||
|
||||
--- @class vim.SystemCompleted
|
||||
--- @field code integer
|
||||
--- @field signal integer
|
||||
--- @field stdout? string
|
||||
--- @field stderr? string
|
||||
|
||||
--- @alias lsp.Client vim.lsp.Client
|
||||
|
||||
compat.system = vim.system
|
||||
-- wrapper around vim.fn.system to give it a similar API to vim.system
|
||||
or function(cmd, _, on_exit)
|
||||
local output = vim.fn.system(cmd)
|
||||
local ok = vim.v.shell_error
|
||||
---@type vim.SystemCompleted
|
||||
local systemObj = {
|
||||
signal = 0,
|
||||
stdout = ok and (output or '') or nil,
|
||||
stderr = not ok and (output or '') or nil,
|
||||
code = vim.v.shell_error,
|
||||
}
|
||||
on_exit(systemObj)
|
||||
return systemObj
|
||||
end
|
||||
|
||||
---@type fun(tbl:table):table
|
||||
compat.tbl_flatten = vim.iter and function(tbl)
|
||||
return vim.iter(tbl):flatten(math.huge):totable()
|
||||
end or vim.tbl_flatten
|
||||
|
||||
return compat
|
||||
@ -7,8 +7,8 @@
|
||||
|
||||
---@brief ]]
|
||||
|
||||
---@class HtConfigCheck
|
||||
local HtConfigCheck = {}
|
||||
---@class haskell-tools.config.Check
|
||||
local Check = {}
|
||||
|
||||
---@param path string
|
||||
---@param msg string|nil
|
||||
@ -29,10 +29,10 @@ local function validate(path, tbl)
|
||||
end
|
||||
|
||||
---Validates the config.
|
||||
---@param cfg HTConfig
|
||||
---@param cfg haskell-tools.Config
|
||||
---@return boolean is_valid
|
||||
---@return string|nil error_message
|
||||
function HtConfigCheck.validate(cfg)
|
||||
function Check.validate(cfg)
|
||||
local ok, err
|
||||
local hls = cfg.hls
|
||||
ok, err = validate('hls', {
|
||||
@ -151,7 +151,7 @@ function HtConfigCheck.validate(cfg)
|
||||
end
|
||||
local auto_discover = dap.auto_discover
|
||||
if type(auto_discover) == 'table' then
|
||||
---@cast auto_discover AddDapConfigOpts
|
||||
---@cast auto_discover haskell-tools.dap.AddConfigOpts
|
||||
ok, err = validate('dap.auto_discover', {
|
||||
autodetect = { auto_discover.autodetect, 'boolean' },
|
||||
settings_file_pattern = { auto_discover.settings_file_pattern, 'string' },
|
||||
@ -169,7 +169,7 @@ end
|
||||
---@param default_tbl table
|
||||
---@param ignored_keys string[]
|
||||
---@return string[]
|
||||
function HtConfigCheck.get_unrecognized_keys(tbl, default_tbl, ignored_keys)
|
||||
function Check.get_unrecognized_keys(tbl, default_tbl, ignored_keys)
|
||||
local unrecognized_keys = {}
|
||||
for k, _ in pairs(tbl) do
|
||||
unrecognized_keys[k] = true
|
||||
@ -183,7 +183,7 @@ function HtConfigCheck.get_unrecognized_keys(tbl, default_tbl, ignored_keys)
|
||||
ret[k] = k
|
||||
end
|
||||
if type(default_tbl[k]) == 'table' and tbl[k] then
|
||||
for _, subk in pairs(HtConfigCheck.get_unrecognized_keys(tbl[k], default_tbl[k], {})) do
|
||||
for _, subk in pairs(Check.get_unrecognized_keys(tbl[k], default_tbl[k], {})) do
|
||||
local key = k .. '.' .. subk
|
||||
ret[key] = key
|
||||
end
|
||||
@ -199,4 +199,4 @@ function HtConfigCheck.get_unrecognized_keys(tbl, default_tbl, ignored_keys)
|
||||
return vim.tbl_keys(ret)
|
||||
end
|
||||
|
||||
return HtConfigCheck
|
||||
return Check
|
||||
|
||||
@ -2,122 +2,223 @@
|
||||
---
|
||||
---@brief [[
|
||||
---To configure haskell-tools.nvim, set the variable `vim.g.haskell_tools`,
|
||||
---which is a `HTOpts` table, in your neovim configuration.
|
||||
---which is a `haskell-tools.Opts` table, in your neovim configuration.
|
||||
---
|
||||
---Example:
|
||||
--->
|
||||
------@type HTOpts
|
||||
------@type haskell-tools.Opts
|
||||
---vim.g.haskell_tools = {
|
||||
--- ---@type ToolsOpts
|
||||
--- ---@type haskell-tools.tools.Opts
|
||||
--- tools = {
|
||||
--- -- ...
|
||||
--- },
|
||||
--- ---@type HaskellLspClientOpts
|
||||
--- ---@type haskell-tools.lsp.ClientOpts
|
||||
--- hls = {
|
||||
--- on_attach = function(client, bufnr)
|
||||
--- -- Set keybindings, etc. here.
|
||||
--- end,
|
||||
--- -- ...
|
||||
--- },
|
||||
--- ---@type HTDapOpts
|
||||
--- ---@type haskell-tools.dap.Opts
|
||||
--- dap = {
|
||||
--- -- ...
|
||||
--- },
|
||||
--- }
|
||||
---<
|
||||
---
|
||||
---Note: `vim.g.haskell_tools` can also be a function that returns a 'HTOpts' table.
|
||||
---Note: `vim.g.haskell_tools` can also be a function that returns a 'haskell-tools.Opts' table.
|
||||
---
|
||||
---@brief ]]
|
||||
|
||||
local config = {}
|
||||
|
||||
---@type (fun():HTOpts) | HTOpts | nil
|
||||
---@type (fun():haskell-tools.Opts) | haskell-tools.Opts | nil
|
||||
vim.g.haskell_tools = vim.g.haskell_tools
|
||||
|
||||
---@class HTOpts
|
||||
---@field tools? ToolsOpts haskell-tools module options.
|
||||
---@field hls? HaskellLspClientOpts haskell-language-server client options.
|
||||
---@field dap? HTDapOpts debug adapter config for nvim-dap.
|
||||
---@class ToolsOpts
|
||||
---@field codeLens? CodeLensOpts LSP codeLens options.
|
||||
---@field hoogle? HoogleOpts Hoogle type signature search options.
|
||||
---@field hover? HoverOpts LSP hover options.
|
||||
---@field definition? DefinitionOpts LSP go-to-definition options.
|
||||
---@field repl? ReplOpts GHCi repl options.
|
||||
---@field tags? FastTagsOpts fast-tags module options.
|
||||
---@field log? HTLogOpts haskell-tools logger options.
|
||||
---@class haskell-tools.Opts
|
||||
---
|
||||
---haskell-tools module options.
|
||||
---@field tools? haskell-tools.tools.Opts
|
||||
---
|
||||
---haskell-language-server client options.
|
||||
---@field hls? haskell-tools.lsp.ClientOpts
|
||||
---
|
||||
---debug adapter config for nvim-dap.
|
||||
---@field dap? haskell-tools.dap.Opts
|
||||
|
||||
---@class CodeLensOpts
|
||||
---@field autoRefresh? (fun():boolean) | boolean (default: `true`) Whether to auto-refresh code-lenses.
|
||||
---@class haskell-tools.tools.Opts
|
||||
---
|
||||
---LSP codeLens options.
|
||||
---@field codeLens? haskell-tools.codeLens.Opts
|
||||
---
|
||||
---Hoogle type signature search options.
|
||||
---@field hoogle? haskell-tools.hoogle.Opts
|
||||
---
|
||||
---LSP hover options.
|
||||
---@field hover? haskell-tools.hover.Opts
|
||||
---LSP go-to-definition options.
|
||||
---@field definition? haskell-tools.definition.Opts
|
||||
---
|
||||
---GHCi repl options.
|
||||
---@field repl? haskell-tools.repl.Opts
|
||||
---
|
||||
---fast-tags module options.
|
||||
---@field tags? haskell-tools.fast-tags.Opts
|
||||
---
|
||||
---haskell-tools logger options.
|
||||
---@field log? haskell-tools.log.Opts
|
||||
|
||||
---@class HoogleOpts
|
||||
---@field mode? HoogleMode Use a telescope with a local hoogle installation or a web backend, or use the browser for hoogle signature search?
|
||||
---@class haskell-tools.codeLens.Opts
|
||||
---
|
||||
---(default: `true`) Whether to auto-refresh code-lenses.
|
||||
---@field autoRefresh? (fun():boolean) | boolean
|
||||
|
||||
---@alias HoogleMode 'auto' | 'telescope-local' | 'telescope-web' | 'browser'
|
||||
---@class haskell-tools.hoogle.Opts
|
||||
---
|
||||
---Use a telescope with a local hoogle installation or a web backend,
|
||||
---or use the browser for hoogle signature search?
|
||||
---@field mode? haskell-tools.hoogle.Mode
|
||||
|
||||
---@class HoverOpts
|
||||
---@field enable? (fun():boolean) | boolean (default: `true`) Whether to enable haskell-tools hover.
|
||||
---@field border? string[][] The hover window's border. Set to `nil` to disable.
|
||||
---@field stylize_markdown? boolean (default: `false`) The builtin LSP client's default behaviour is to stylize markdown. Setting this option to false sets the file type to markdown and enables treesitter syntax highligting for Haskell snippets if nvim-treesitter is installed.
|
||||
---@field auto_focus? boolean (default: `false`) Whether to automatically switch to the hover window.
|
||||
---@alias haskell-tools.hoogle.Mode 'auto' | 'telescope-local' | 'telescope-web' | 'browser'
|
||||
|
||||
---@class DefinitionOpts
|
||||
---@field hoogle_signature_fallback? (fun():boolean) | boolean (default: `false`) Configure `vim.lsp.definition` to fall back to hoogle search (does not affect `vim.lsp.tagfunc`).
|
||||
---@class haskell-tools.hover.Opts
|
||||
---
|
||||
---(default: `true`) Whether to enable haskell-tools hover.
|
||||
---@field enable? (fun():boolean) | boolean
|
||||
---
|
||||
---The hover window's border. Set to `nil` to disable.
|
||||
---@field border? string[][]
|
||||
---
|
||||
---(default: `false`) The builtin LSP client's default behaviour is to stylize markdown.
|
||||
---Setting this option to false sets the file type to markdown
|
||||
---and enables treesitter syntax highligting for Haskell snippets if nvim-treesitter is installed.
|
||||
---@field stylize_markdown? boolean
|
||||
---
|
||||
---(default: `false`) Whether to automatically switch to the hover window.
|
||||
---@field auto_focus? boolean
|
||||
|
||||
---@class ReplOpts
|
||||
---@field handler? (fun():ReplHandler) | ReplHandler `'builtin'`: Use the simple builtin repl. `'toggleterm'`: Use akinsho/toggleterm.nvim.
|
||||
---@field prefer? (fun():repl_backend) | repl_backend Prefer cabal or stack when both stack and cabal project files are present?
|
||||
---@field builtin? BuiltinReplOpts Configuration for the builtin repl.
|
||||
---@field auto_focus? boolean Whether to auto-focus the repl on toggle or send. If unset, the handler decides.
|
||||
---@class haskell-tools.definition.Opts
|
||||
---
|
||||
---(default: `false`) Configure |vim.lsp.definition| to fall back to hoogle search
|
||||
---(does not affect |vim.lsp.tagfunc|).
|
||||
---@field hoogle_signature_fallback? (fun():boolean) | boolean
|
||||
|
||||
---@alias ReplHandler 'builtin' | 'toggleterm'
|
||||
---@alias repl_backend 'cabal' | 'stack'
|
||||
---@class haskell-tools.repl.Opts
|
||||
---
|
||||
---`'builtin'`: Use the simple builtin repl.
|
||||
---`'toggleterm'`: Use akinsho/toggleterm.nvim.
|
||||
---@field handler? (fun():haskell-tools.repl.Handler) | haskell-tools.repl.Handler
|
||||
---
|
||||
---Prefer cabal or stack when both stack and cabal project files are present?
|
||||
---@field prefer? (fun():haskell-tools.repl.Backend) | haskell-tools.repl.Backend
|
||||
---
|
||||
---Configuration for the builtin repl.
|
||||
---@field builtin? haskell-tools.repl.builtin.Opts
|
||||
---
|
||||
---Whether to auto-focus the repl on toggle or send. If unset, the handler decides.
|
||||
---@field auto_focus? boolean
|
||||
|
||||
---@class BuiltinReplOpts
|
||||
---@field create_repl_window? (fun(view:ReplView):fun(mk_repl_cmd:mk_repl_cmd_fun)) How to create the repl window. Should return a function that calls one of the `ReplView`'s functions.
|
||||
---@alias haskell-tools.repl.Handler 'builtin' | 'toggleterm'
|
||||
---@alias haskell-tools.repl.Backend 'cabal' | 'stack'
|
||||
|
||||
---@class ReplView
|
||||
---@field create_repl_split? fun(opts:ReplViewOpts):mk_repl_cmd_fun Create the REPL in a horizontally split window.
|
||||
---@field create_repl_vsplit? fun(opts:ReplViewOpts):mk_repl_cmd_fun Create the REPL in a vertically split window.
|
||||
---@field create_repl_tabnew? fun(opts:ReplViewOpts):mk_repl_cmd_fun Create the REPL in a new tab.
|
||||
---@field create_repl_cur_win? fun(opts:ReplViewOpts):mk_repl_cmd_fun Create the REPL in the current window.
|
||||
---@class haskell-tools.repl.builtin.Opts
|
||||
---
|
||||
---How to create the repl window.
|
||||
---Should return a function that calls one of the |haskell-tools.repl.View|'s functions.
|
||||
---@field create_repl_window? (fun(view:haskell-tools.repl.View):fun(mk_repl_cmd:mk_ht_repl_cmd_fun))
|
||||
|
||||
---@class ReplViewOpts
|
||||
---@field delete_buffer_on_exit? boolean Whether to delete the buffer when the Repl quits.
|
||||
---@field size? (fun():number) | number The size of the window or a function that determines it.
|
||||
---@class haskell-tools.repl.View
|
||||
---
|
||||
---Create the REPL in a horizontally split window.
|
||||
---@field create_repl_split? fun(opts:haskell-tools.repl.view.Opts):mk_ht_repl_cmd_fun
|
||||
---
|
||||
---Create the REPL in a vertically split window.
|
||||
---@field create_repl_vsplit? fun(opts:haskell-tools.repl.view.Opts):mk_ht_repl_cmd_fun
|
||||
---
|
||||
---Create the REPL in a new tab.
|
||||
---@field create_repl_tabnew? fun(opts:haskell-tools.repl.view.Opts):mk_ht_repl_cmd_fun
|
||||
---
|
||||
---Create the REPL in the current window.
|
||||
---@field create_repl_cur_win? fun(opts:haskell-tools.repl.view.Opts):mk_ht_repl_cmd_fun
|
||||
|
||||
---@alias mk_repl_cmd_fun fun():(string[]|nil)
|
||||
---@class haskell-tools.repl.view.Opts
|
||||
---
|
||||
---Whether to delete the buffer when the Repl quits.
|
||||
---@field delete_buffer_on_exit? boolean
|
||||
---
|
||||
---The size of the window or a function that determines it.
|
||||
---@field size? (fun():number) | number
|
||||
|
||||
---@class FastTagsOpts
|
||||
---@field enable? boolean | (fun():boolean) Enabled by default if the `fast-tags` executable is found.
|
||||
---@field package_events? string[] `autocmd` Events to trigger package tag generation.
|
||||
---@alias mk_ht_repl_cmd_fun fun():(string[]|nil)
|
||||
|
||||
---@class HTLogOpts
|
||||
---@field level? number | string The log level.
|
||||
---@class haskell-tools.fast-tags.Opts
|
||||
---
|
||||
---Enabled by default if the `fast-tags` executable is found.
|
||||
---@field enable? boolean | (fun():boolean)
|
||||
---
|
||||
---The |autocmd| events to trigger package tag generation.
|
||||
---@field package_events? string[]
|
||||
|
||||
---@class haskell-tools.log.Opts
|
||||
---
|
||||
---The log level.
|
||||
---@field level? number | string
|
||||
---@see vim.log.levels
|
||||
|
||||
---@class HaskellLspClientOpts
|
||||
---@field auto_attach? (fun():boolean) | boolean Whether to automatically attach the LSP client. Defaults to `true` if the haskell-language-server executable is found.
|
||||
---@field debug? boolean Whether to enable haskell-language-server debug logging.
|
||||
---@field on_attach? fun(client:number,bufnr:number,ht:HaskellTools) Callback that is invoked when the client attaches to a buffer.
|
||||
---@field cmd? (fun():string[]) | string[] The command to start haskell-language-server with.
|
||||
---@field capabilities? lsp.ClientCapabilities LSP client capabilities.
|
||||
---@field settings? (fun(project_root:string|nil):table) | table The haskell-language-server settings or a function that creates them. To view the default settings, run `haskell-language-server generate-default-config`.
|
||||
---@field default_settings? table The default haskell-language-server settings that will be used if no settings are specified or detected.
|
||||
---@field logfile? string The path to the haskell-language-server log file.
|
||||
---@class haskell-tools.lsp.ClientOpts
|
||||
---
|
||||
---Whether to automatically attach the LSP client.
|
||||
---Defaults to `true` if the haskell-language-server executable is found.
|
||||
---@field auto_attach? (fun():boolean) | boolean
|
||||
---
|
||||
---Whether to enable haskell-language-server debug logging.
|
||||
---@field debug? boolean
|
||||
---
|
||||
---Callback that is invoked when the client attaches to a buffer.
|
||||
---@field on_attach? fun(client:number,bufnr:number,ht:HaskellTools)
|
||||
---
|
||||
---The command to start haskell-language-server with.
|
||||
---@field cmd? (fun():string[]) | string[]
|
||||
---
|
||||
---LSP client capabilities.
|
||||
---@field capabilities? lsp.ClientCapabilities
|
||||
---
|
||||
---The haskell-language-server settings or a function that creates them.
|
||||
--- To view the default settings, run `haskell-language-server generate-default-config`.
|
||||
---@field settings? (fun(project_root:string|nil):table) | table
|
||||
---
|
||||
---The default haskell-language-server settings that will be used if no settings are specified or detected.
|
||||
---@field default_settings? table
|
||||
---
|
||||
---The path to the haskell-language-server log file.
|
||||
---@field logfile? string
|
||||
|
||||
---@brief [[
|
||||
--- To print all options that are available for your haskell-language-server version, run `haskell-language-server-wrapper generate-default-config`
|
||||
---See: https://haskell-language-server.readthedocs.io/en/latest/configuration.html.
|
||||
---@brief ]]
|
||||
|
||||
---@class HTDapOpts
|
||||
---@field cmd? string[] The command to start the debug adapter server with.
|
||||
---@field logFile? string Log file path for detected configurations.
|
||||
---@field logLevel? HaskellDebugAdapterLogLevel The log level for detected configurations.
|
||||
---@field auto_discover? boolean | AddDapConfigOpts Set to `false` to disable auto-discovery of launch configurations. `true` uses the default configurations options`.
|
||||
---@class haskell-tools.dap.Opts
|
||||
---
|
||||
---The command to start the debug adapter server with.
|
||||
---@field cmd? string[]
|
||||
---
|
||||
---Log file path for detected configurations.
|
||||
---@field logFile? string
|
||||
---
|
||||
---The log level for detected configurations.
|
||||
---@field logLevel? haskell-tools.debugAdapter.LogLevel
|
||||
---@field auto_discover? boolean | haskell-tools.dap.AddConfigOpts Set to `false` to disable auto-discovery of launch configurations. `true` uses the default configurations options`.
|
||||
|
||||
---@alias HaskellDebugAdapterLogLevel 'Debug' | 'Info' | 'Warning' | 'Error'
|
||||
---@alias haskell-tools.debugAdapter.LogLevel 'Debug' | 'Info' | 'Warning' | 'Error'
|
||||
|
||||
---@class haskell-tools.dap.AddConfigOpts
|
||||
---
|
||||
---Whether to automatically detect launch configurations for the project.
|
||||
---@field autodetect boolean
|
||||
---
|
||||
---File name or pattern to search for.
|
||||
---Defaults to 'launch.json'.
|
||||
---@field settings_file_pattern string
|
||||
|
||||
return config
|
||||
|
||||
@ -10,9 +10,8 @@
|
||||
---@brief ]]
|
||||
|
||||
local deps = require('haskell-tools.deps')
|
||||
local compat = require('haskell-tools.compat')
|
||||
|
||||
---@type HTConfig
|
||||
---@type haskell-tools.Config
|
||||
local HTConfig = {}
|
||||
|
||||
local ht_capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||
@ -40,22 +39,22 @@ local capabilities = vim.tbl_deep_extend(
|
||||
folding_range_capabilities
|
||||
)
|
||||
|
||||
---@class HTConfig haskell-tools.nvim plugin configuration.
|
||||
---@class haskell-tools.Config haskell-tools.nvim plugin configuration.
|
||||
local HTDefaultConfig = {
|
||||
|
||||
---@class ToolsConfig haskell-tools module config.
|
||||
---@class haskell-tools.tools.Config haskell-tools module config.
|
||||
tools = {
|
||||
---@class CodeLensConfig LSP codeLens options.
|
||||
---@class haskell-tools.codeLens.Config LSP codeLens options.
|
||||
codeLens = {
|
||||
---@type boolean | (fun():boolean) (default: `true`) Whether to auto-refresh code-lenses.
|
||||
autoRefresh = true,
|
||||
},
|
||||
---@class HoogleConfig hoogle type signature search config.
|
||||
---@class haskell-tools.hoogle.Config hoogle type signature search config.
|
||||
hoogle = {
|
||||
---@type HoogleMode Use a telescope with a local hoogle installation or a web backend, or use the browser for hoogle signature search?
|
||||
---@type haskell-tools.hoogle.Mode Use a telescope with a local hoogle installation or a web backend, or use the browser for hoogle signature search?
|
||||
mode = 'auto',
|
||||
},
|
||||
---@class HoverConfig Enhanced LSP hover options.
|
||||
---@class haskell-tools.hover.Config Enhanced LSP hover options.
|
||||
hover = {
|
||||
---@type boolean | (fun():boolean) (default: `true`) Whether to enable haskell-tools hover.
|
||||
enable = true,
|
||||
@ -75,22 +74,22 @@ local HTDefaultConfig = {
|
||||
---@type boolean (default: `false`) Whether to automatically switch to the hover window.
|
||||
auto_focus = false,
|
||||
},
|
||||
---@class DefinitionConfig Enhanced LSP go-to-definition options.
|
||||
---@class haskell-tools.definition.Config Enhanced LSP go-to-definition options.
|
||||
definition = {
|
||||
---@type boolean | (fun():boolean) (default: `false`) Configure `vim.lsp.definition` to fall back to hoogle search (does not affect `vim.lsp.tagfunc`).
|
||||
hoogle_signature_fallback = false,
|
||||
},
|
||||
---@class ReplConfig GHCi repl options.
|
||||
---@class haskell-tools.repl.Config GHCi repl options.
|
||||
repl = {
|
||||
---@type ReplHandler | (fun():ReplHandler) `'builtin'`: Use the simple builtin repl. `'toggleterm'`: Use akinsho/toggleterm.nvim.
|
||||
---@type haskell-tools.repl.Handler | (fun():haskell-tools.repl.Handler) `'builtin'`: Use the simple builtin repl. `'toggleterm'`: Use akinsho/toggleterm.nvim.
|
||||
handler = 'builtin',
|
||||
---@type repl_backend | (fun():repl_backend) Prefer cabal or stack when both stack and cabal project files are present?
|
||||
---@type haskell-tools.repl.Backend | (fun():haskell-tools.repl.Backend) Prefer cabal or stack when both stack and cabal project files are present?
|
||||
prefer = function()
|
||||
return vim.fn.executable('stack') == 1 and 'stack' or 'cabal'
|
||||
end,
|
||||
---@class BuiltinReplConfig Configuration for the builtin repl
|
||||
---@class haskell-tools.repl.builtin.Config Configuration for the builtin repl
|
||||
builtin = {
|
||||
---@type fun(view:ReplView):fun(mk_repl_cmd:mk_repl_cmd_fun) How to create the repl window. Should return a function that calls one of the `ReplView`'s functions.
|
||||
---@type fun(view:haskell-tools.repl.View):fun(mk_repl_cmd:mk_ht_repl_cmd_fun) How to create the repl window. Should return a function that calls one of the `ReplView`'s functions.
|
||||
create_repl_window = function(view)
|
||||
return view.create_repl_split { size = vim.o.lines / 3 }
|
||||
end,
|
||||
@ -98,7 +97,7 @@ local HTDefaultConfig = {
|
||||
---@type boolean | nil Whether to auto-focus the repl on toggle or send. If unset, the handler decides.
|
||||
auto_focus = nil,
|
||||
},
|
||||
---@class FastTagsConfig fast-tags module options.
|
||||
---@class haskell-tools.fast-tags.Config fast-tags module options.
|
||||
tags = {
|
||||
---@type boolean | (fun():boolean) Enabled by default if the `fast-tags` executable is found.
|
||||
enable = function()
|
||||
@ -107,16 +106,16 @@ local HTDefaultConfig = {
|
||||
---@type string[] `autocmd` Events to trigger package tag generation.
|
||||
package_events = { 'BufWritePost' },
|
||||
},
|
||||
---@class HTLogConfig haskell-tools logger options.
|
||||
---@class haskell-tools.log.Config haskell-tools logger options.
|
||||
log = {
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
logfile = compat.joinpath(vim.fn.stdpath('log'), 'haskell-tools.log'),
|
||||
logfile = vim.fs.joinpath(vim.fn.stdpath('log'), 'haskell-tools.log'),
|
||||
---@type number | string The log level.
|
||||
---@see vim.log.levels
|
||||
level = vim.log.levels.WARN,
|
||||
},
|
||||
},
|
||||
---@class HaskellLspClientConfig haskell-language-server client options.
|
||||
---@class haskell-tools.lsp.ClientConfig haskell-language-server client options.
|
||||
hls = {
|
||||
---@type boolean | (fun():boolean) Whether to automatically attach the LSP client. Defaults to `true` if the haskell-language-server executable is found.
|
||||
auto_attach = function()
|
||||
@ -250,15 +249,15 @@ local HTDefaultConfig = {
|
||||
---@type string The path to the haskell-language-server log file.
|
||||
logfile = vim.fn.tempname() .. '-haskell-language-server.log',
|
||||
},
|
||||
---@class HTDapConfig debug adapter config for nvim-dap.
|
||||
---@class haskell-tools.dap.Config debug adapter config for nvim-dap.
|
||||
dap = {
|
||||
---@type string[] | (fun():string[]) The command to start the debug adapter server with.
|
||||
cmd = { 'haskell-debug-adapter' },
|
||||
---@type string Log file path for detected configurations.
|
||||
logFile = vim.fn.stdpath('data') .. '/haskell-dap.log',
|
||||
---@type HaskellDebugAdapterLogLevel The log level for detected configurations.
|
||||
---@type haskell-tools.debugAdapter.LogLevel The log level for detected configurations.
|
||||
logLevel = 'Warning',
|
||||
---@type boolean | AddDapConfigOpts Set to `false` to disable auto-discovery of launch configurations. `true` uses the default configurations options`.
|
||||
---@type boolean | haskell-tools.dap.AddConfigOpts Set to `false` to disable auto-discovery of launch configurations. `true` uses the default configurations options`.
|
||||
auto_discover = true,
|
||||
},
|
||||
debug_info = {
|
||||
@ -268,10 +267,10 @@ local HTDefaultConfig = {
|
||||
}
|
||||
|
||||
local haskell_tools = vim.g.haskell_tools or {}
|
||||
---@type HTOpts
|
||||
---@type haskell-tools.Opts
|
||||
local opts = type(haskell_tools) == 'function' and haskell_tools() or haskell_tools
|
||||
|
||||
---@type HTConfig
|
||||
---@type haskell-tools.Config
|
||||
HTConfig = vim.tbl_deep_extend('force', {}, HTDefaultConfig, opts)
|
||||
local check = require('haskell-tools.config.check')
|
||||
local ok, err = check.validate(HTConfig)
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
local deps = require('haskell-tools.deps')
|
||||
local Types = require('haskell-tools.types.internal')
|
||||
local compat = require('haskell-tools.compat')
|
||||
|
||||
---@param root_dir string
|
||||
local function get_ghci_dap_cmd(root_dir)
|
||||
@ -15,13 +14,13 @@ local function get_ghci_dap_cmd(root_dir)
|
||||
end
|
||||
|
||||
---@param root_dir string
|
||||
---@param opts AddDapConfigOpts
|
||||
---@return HsDapLaunchConfiguration[]
|
||||
---@param opts haskell-tools.dap.AddConfigOpts
|
||||
---@return haskell-tools.dap.LaunchConfiguration[]
|
||||
local function find_json_configurations(root_dir, opts)
|
||||
---@type HsDapLaunchConfiguration[]
|
||||
---@type haskell-tools.dap.LaunchConfiguration[]
|
||||
local configurations = {}
|
||||
local log = require('haskell-tools.log.internal')
|
||||
local results = vim.fn.glob(compat.joinpath(root_dir, opts.settings_file_pattern), true, true)
|
||||
local results = vim.fn.glob(vim.fs.joinpath(root_dir, opts.settings_file_pattern), true, true)
|
||||
if #results == 0 then
|
||||
log.info(opts.settings_file_pattern .. ' not found in project root ' .. root_dir)
|
||||
else
|
||||
@ -41,21 +40,21 @@ local function find_json_configurations(root_dir, opts)
|
||||
end
|
||||
|
||||
---@param root_dir string
|
||||
---@return HsDapLaunchConfiguration[]
|
||||
---@return haskell-tools.dap.LaunchConfiguration[]
|
||||
local function detect_launch_configurations(root_dir)
|
||||
local launch_configurations = {}
|
||||
local HTConfig = require('haskell-tools.config.internal')
|
||||
local dap_opts = HTConfig.dap
|
||||
---@param entry_point HsEntryPoint
|
||||
---@return HsDapLaunchConfiguration
|
||||
---@param entry_point haskell-tools.EntryPoint
|
||||
---@return haskell-tools.dap.LaunchConfiguration
|
||||
local function mk_launch_configuration(entry_point)
|
||||
---@class HsDapLaunchConfiguration
|
||||
local HsDapLaunchConfiguration = {
|
||||
---@class haskell-tools.dap.LaunchConfiguration
|
||||
local LaunchConfiguration = {
|
||||
type = 'ghc',
|
||||
request = 'launch',
|
||||
name = entry_point.package_name .. ':' .. entry_point.exe_name,
|
||||
workspace = '${workspaceFolder}',
|
||||
startup = compat.joinpath(entry_point.package_dir, entry_point.source_dir, entry_point.main),
|
||||
startup = vim.fs.joinpath(entry_point.package_dir, entry_point.source_dir, entry_point.main),
|
||||
startupFunc = '', -- defaults to 'main' if not set
|
||||
startupArgs = '',
|
||||
stopOnEntry = false,
|
||||
@ -68,7 +67,7 @@ local function detect_launch_configurations(root_dir)
|
||||
ghciCmd = get_ghci_dap_cmd(root_dir),
|
||||
forceInspect = false,
|
||||
}
|
||||
return HsDapLaunchConfiguration
|
||||
return LaunchConfiguration
|
||||
end
|
||||
local HtProjectHelpers = require('haskell-tools.project.helpers')
|
||||
for _, entry_point in pairs(HtProjectHelpers.parse_project_entrypoints(root_dir)) do
|
||||
@ -81,7 +80,7 @@ end
|
||||
local _configuration_cache = {}
|
||||
|
||||
if not deps.has('dap') then
|
||||
---@type HsDapTools
|
||||
---@type haskell-tools.Dap
|
||||
local NullHsDapTools = {
|
||||
discover_configurations = function(_) end,
|
||||
}
|
||||
@ -90,22 +89,20 @@ end
|
||||
|
||||
local dap = require('dap')
|
||||
|
||||
---@class HsDapTools
|
||||
local HsDapTools = {}
|
||||
---@class haskell-tools.Dap
|
||||
local Dap = {}
|
||||
|
||||
---@class AddDapConfigOpts
|
||||
---@type haskell-tools.dap.AddConfigOpts
|
||||
local DefaultAutoDapConfigOpts = {
|
||||
---@type boolean Whether to automatically detect launch configurations for the project.
|
||||
autodetect = true,
|
||||
---@type string File name or pattern to search for. Defaults to 'launch.json'.
|
||||
settings_file_pattern = 'launch.json',
|
||||
}
|
||||
|
||||
---Discover nvim-dap launch configurations for haskell-debug-adapter.
|
||||
---@param bufnr number|nil The buffer number
|
||||
---@param opts AddDapConfigOpts|nil
|
||||
---@param opts haskell-tools.dap.AddConfigOpts|nil
|
||||
---@return nil
|
||||
HsDapTools.discover_configurations = function(bufnr, opts)
|
||||
Dap.discover_configurations = function(bufnr, opts)
|
||||
local HTConfig = require('haskell-tools.config.internal')
|
||||
local HTDapConfig = HTConfig.dap
|
||||
local log = require('haskell-tools.log.internal')
|
||||
@ -140,7 +137,7 @@ HsDapTools.discover_configurations = function(bufnr, opts)
|
||||
vim.list_extend(discovered_configurations, detected_configurations)
|
||||
end
|
||||
_configuration_cache[project_root] = discovered_configurations
|
||||
---@type HsDapLaunchConfiguration[]
|
||||
---@type haskell-tools.dap.LaunchConfiguration[]
|
||||
local dap_configurations = dap.configurations.haskell or {}
|
||||
for _, cfg in ipairs(discovered_configurations) do
|
||||
for i, existing_config in pairs(dap_configurations) do
|
||||
@ -153,4 +150,4 @@ HsDapTools.discover_configurations = function(bufnr, opts)
|
||||
dap.configurations.haskell = dap_configurations
|
||||
end
|
||||
|
||||
return HsDapTools
|
||||
return Dap
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
local compat = require('haskell-tools.compat')
|
||||
|
||||
---@class DapInternal
|
||||
---@class haskell-tools.internal.Dap
|
||||
local Dap = {}
|
||||
|
||||
---@param package_name string
|
||||
@ -8,13 +6,13 @@ local Dap = {}
|
||||
---@param package_dir string
|
||||
---@param mains string[]
|
||||
---@param source_dirs string[]
|
||||
---@return HsEntryPoint[] entry_points
|
||||
---@return haskell-tools.EntryPoint[] entry_points
|
||||
Dap.mk_entry_points = function(package_name, exe_name, package_dir, mains, source_dirs)
|
||||
---@type HsEntryPoint[]
|
||||
---@type haskell-tools.EntryPoint[]
|
||||
local entry_points = {}
|
||||
for _, source_dir in pairs(source_dirs) do
|
||||
for _, main in pairs(mains) do
|
||||
local filename = compat.joinpath(package_dir, source_dir, main)
|
||||
local filename = vim.fs.joinpath(package_dir, source_dir, main)
|
||||
if vim.fn.filereadable(filename) == 1 then
|
||||
local entry_point = {
|
||||
package_name = package_name,
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
---@brief ]]
|
||||
|
||||
---@class Deps
|
||||
---@class haskell-tools.Deps
|
||||
local Deps = {}
|
||||
|
||||
---@param modname string The name of the module
|
||||
|
||||
@ -22,13 +22,13 @@ local error = h.error or h.report_error
|
||||
---@diagnostic disable-next-line: deprecated
|
||||
local warn = h.warn or h.report_warn
|
||||
|
||||
---@class LuaDependency
|
||||
---@class haskell-tools.LuaDependency
|
||||
---@field module string The name of a module
|
||||
---@field optional fun():boolean Function that returns whether the dependency is optional
|
||||
---@field url string URL (markdown)
|
||||
---@field info string Additional information
|
||||
|
||||
---@type LuaDependency[]
|
||||
---@type haskell-tools.LuaDependency[]
|
||||
local lua_dependencies = {
|
||||
{
|
||||
module = 'telescope',
|
||||
@ -44,7 +44,7 @@ local lua_dependencies = {
|
||||
},
|
||||
}
|
||||
|
||||
---@class ExternalDependency
|
||||
---@class haskell-tools.ExternalDependency
|
||||
---@field name string Name of the dependency
|
||||
---@field get_binaries fun():string[]Function that returns the binaries to check for
|
||||
---@field optional fun():boolean Function that returns whether the dependency is optional
|
||||
@ -52,7 +52,7 @@ local lua_dependencies = {
|
||||
---@field info string Additional information
|
||||
---@field extra_checks function|nil Optional extra checks to perform if the dependency is installed
|
||||
|
||||
---@type ExternalDependency[]
|
||||
---@type haskell-tools.ExternalDependency[]
|
||||
local external_dependencies = {
|
||||
{
|
||||
name = 'haskell-language-server',
|
||||
@ -153,7 +153,7 @@ local external_dependencies = {
|
||||
},
|
||||
}
|
||||
|
||||
---@param dep LuaDependency
|
||||
---@param dep haskell-tools.LuaDependency
|
||||
local function check_lua_dependency(dep)
|
||||
if deps.has(dep.module) then
|
||||
ok(dep.url .. ' installed.')
|
||||
@ -166,7 +166,7 @@ local function check_lua_dependency(dep)
|
||||
end
|
||||
end
|
||||
|
||||
---@param dep ExternalDependency
|
||||
---@param dep haskell-tools.ExternalDependency
|
||||
---@return boolean is_installed
|
||||
---@return string|nil version
|
||||
local check_installed = function(dep)
|
||||
@ -188,7 +188,7 @@ local check_installed = function(dep)
|
||||
return false
|
||||
end
|
||||
|
||||
---@param dep ExternalDependency
|
||||
---@param dep haskell-tools.ExternalDependency
|
||||
local function check_external_dependency(dep)
|
||||
local installed, mb_version = check_installed(dep)
|
||||
if installed then
|
||||
|
||||
@ -17,13 +17,13 @@ local actions = deps.require_telescope('telescope.actions')
|
||||
local actions_state = deps.require_telescope('telescope.actions.state')
|
||||
local entry_display = deps.require_telescope('telescope.pickers.entry_display')
|
||||
|
||||
---@class HoogleHelpers
|
||||
local HoogleHelpers = {}
|
||||
---@class haskell-tools.hoogle.Helpers
|
||||
local Helpers = {}
|
||||
|
||||
---@param buf number the telescope buffebuffer numberr
|
||||
---@param map fun(mode:string,keys:string,action:function) callback for creating telescope keymaps
|
||||
---@return boolean
|
||||
function HoogleHelpers.hoogle_attach_mappings(buf, map)
|
||||
function Helpers.hoogle_attach_mappings(buf, map)
|
||||
actions.select_default:replace(function()
|
||||
-- Copy type signature to clipboard
|
||||
local entry = actions_state.get_selected_entry()
|
||||
@ -57,19 +57,19 @@ local function format_html(html)
|
||||
return html and html:gsub('<', '<'):gsub('>', '>'):gsub('&', '&') or ''
|
||||
end
|
||||
|
||||
---@class TelescopeHoogleEntry
|
||||
---@class haskell-tools.hoogle.telescope.Entry
|
||||
---@field value string
|
||||
---@field valid boolean
|
||||
---@field type_sig string The entry's type signature
|
||||
---@field module_name string The name of the module that contains the entry
|
||||
---@field url string|nil The entry's Hackage URL
|
||||
---@field docs string|nil The Hoogle entry's documentation
|
||||
---@field display fun(TelescopeHoogleEntry):TelescopeDisplay
|
||||
---@field display fun(TelescopeHoogleEntry):haskell-tools.telescope.Display
|
||||
---@field ordinal string
|
||||
---@field preview_command fun(TelescopeHoogleEntry, number):nil
|
||||
|
||||
---Show a preview in the Telescope previewer
|
||||
---@param entry TelescopeHoogleEntry
|
||||
---@param entry haskell-tools.hoogle.telescope.Entry
|
||||
---@param buf number the Telescope preview buffer
|
||||
local function show_preview(entry, buf)
|
||||
local docs = format_html(entry.docs)
|
||||
@ -85,10 +85,10 @@ local function show_preview(entry, buf)
|
||||
end)
|
||||
end
|
||||
|
||||
---@class TelescopeDisplay
|
||||
---@class haskell-tools.telescope.Display
|
||||
|
||||
---@param entry TelescopeHoogleEntry
|
||||
---@return TelescopeDisplay
|
||||
---@param entry haskell-tools.hoogle.telescope.Entry
|
||||
---@return haskell-tools.telescope.Display
|
||||
local function make_display(entry)
|
||||
local module = entry.module_name
|
||||
|
||||
@ -114,18 +114,18 @@ local function get_type_sig(hoogle_item)
|
||||
return hoogle_item
|
||||
end
|
||||
|
||||
---@class HoogleData
|
||||
---@field module HoogleModule|nil
|
||||
---@class haskell-tools.hoogle.Data
|
||||
---@field module haskell-tools.hoogle.Module|nil
|
||||
---@field item string|nil
|
||||
---@field url string|nil
|
||||
---@field docs string|nil
|
||||
|
||||
---@class HoogleModule
|
||||
---@class haskell-tools.hoogle.Module
|
||||
---@field name string
|
||||
|
||||
---@param data HoogleData
|
||||
---@return TelescopeHoogleEntry|nil
|
||||
function HoogleHelpers.mk_hoogle_entry(data)
|
||||
---@param data haskell-tools.hoogle.Data
|
||||
---@return haskell-tools.hoogle.telescope.Entry|nil
|
||||
function Helpers.mk_hoogle_entry(data)
|
||||
local module_name = (data.module or {}).name
|
||||
local type_sig = data.item and get_type_sig(data.item) or ''
|
||||
if not module_name or not type_sig then
|
||||
@ -144,4 +144,4 @@ function HoogleHelpers.mk_hoogle_entry(data)
|
||||
}
|
||||
end
|
||||
|
||||
return HoogleHelpers
|
||||
return Helpers
|
||||
|
||||
@ -87,12 +87,12 @@ elseif opts.mode == 'auto' then
|
||||
end
|
||||
end
|
||||
|
||||
---@class HoogleTools
|
||||
local HoogleTools = {}
|
||||
---@class haskell-tools.Hoogle
|
||||
local Hoogle = {}
|
||||
|
||||
---@param options table<string,any>|nil Includes the `search_term` and options to pass to the telescope picker (if available)
|
||||
---@return nil
|
||||
HoogleTools.hoogle_signature = function(options)
|
||||
Hoogle.hoogle_signature = function(options)
|
||||
options = options or {}
|
||||
log.debug { 'Hoogle signature search options', options }
|
||||
if options.search_term then
|
||||
@ -111,4 +111,4 @@ HoogleTools.hoogle_signature = function(options)
|
||||
end
|
||||
end
|
||||
|
||||
return HoogleTools
|
||||
return Hoogle
|
||||
|
||||
@ -9,35 +9,34 @@
|
||||
|
||||
local log = require('haskell-tools.log.internal')
|
||||
local deps = require('haskell-tools.deps')
|
||||
local compat = require('haskell-tools.compat')
|
||||
|
||||
---@class LocalHoogleHandler
|
||||
local HoogleLocal = {}
|
||||
---@class haskell-tools.hoogle.handler.Local
|
||||
local Local = {}
|
||||
|
||||
---@return boolean has_hoogle `true` if the `hoogle` executable exists
|
||||
function HoogleLocal.has_hoogle()
|
||||
function Local.has_hoogle()
|
||||
return vim.fn.executable('hoogle') == 1
|
||||
end
|
||||
|
||||
if not HoogleLocal.has_hoogle() then
|
||||
return HoogleLocal
|
||||
if not Local.has_hoogle() then
|
||||
return Local
|
||||
end
|
||||
|
||||
if not deps.has_telescope() then
|
||||
return HoogleLocal
|
||||
return Local
|
||||
end
|
||||
|
||||
---@class LocalHoogleOpts
|
||||
---@class haskell-tools.hoogle.handler.Local.Opts
|
||||
---@field entry_maker function|nil telescope entry maker
|
||||
---@field count number|nil number of results to display
|
||||
|
||||
---Construct the hoogle cli arguments
|
||||
---@param search_term string The Hoogle search term
|
||||
---@param opts LocalHoogleOpts
|
||||
---@param opts haskell-tools.hoogle.handler.Local.Opts
|
||||
---@return string[] hoogle_args
|
||||
local function mk_hoogle_args(search_term, opts)
|
||||
local count = opts.count or 50
|
||||
local args = compat.tbl_flatten { '--json', '--count=' .. count, search_term }
|
||||
local args = vim.iter({ '--json', '--count=' .. count, search_term }):flatten():totable()
|
||||
log.debug { 'Hoogle local args', args }
|
||||
return args
|
||||
end
|
||||
@ -48,9 +47,9 @@ local previewers = deps.require_telescope('telescope.previewers')
|
||||
local HoogleHelpers = require('haskell-tools.hoogle.helpers')
|
||||
|
||||
---@param search_term string The Hoogle search term
|
||||
---@param opts LocalHoogleOpts|nil
|
||||
---@param opts haskell-tools.hoogle.handler.Local.Opts|nil
|
||||
---@return nil
|
||||
function HoogleLocal.telescope_search(search_term, opts)
|
||||
function Local.telescope_search(search_term, opts)
|
||||
opts = opts or {}
|
||||
opts.entry_maker = opts.entry_maker or HoogleHelpers.mk_hoogle_entry
|
||||
local config = deps.require_telescope('telescope.config').values
|
||||
@ -61,7 +60,7 @@ function HoogleLocal.telescope_search(search_term, opts)
|
||||
return
|
||||
end
|
||||
local cmd = vim.list_extend({ 'hoogle' }, mk_hoogle_args(search_term, opts))
|
||||
compat.system(
|
||||
vim.system(
|
||||
cmd,
|
||||
nil,
|
||||
vim.schedule_wrap(function(result)
|
||||
@ -99,4 +98,4 @@ function HoogleLocal.telescope_search(search_term, opts)
|
||||
)
|
||||
end
|
||||
|
||||
return HoogleLocal
|
||||
return Local
|
||||
|
||||
@ -10,9 +10,8 @@
|
||||
local log = require('haskell-tools.log.internal')
|
||||
local deps = require('haskell-tools.deps')
|
||||
local OS = require('haskell-tools.os')
|
||||
local compat = require('haskell-tools.compat')
|
||||
|
||||
---@class WebHoogleHandler
|
||||
---@class haskell-tools.hoogle.handler.Web
|
||||
local WebHoogleHandler = {}
|
||||
|
||||
---@param c string A single character
|
||||
@ -31,16 +30,16 @@ local function urlencode(url)
|
||||
return url
|
||||
end
|
||||
|
||||
---@class TelescopeHoogleWebOpts
|
||||
---@field hoogle HoogleWebSearchOpts|nil
|
||||
---@class haskell-tools.hoogle.telescope.web.Opts
|
||||
---@field hoogle haskell-tools.hoogle.web-search.Opts|nil
|
||||
|
||||
---@class HoogleWebSearchOpts
|
||||
---@class haskell-tools.hoogle.web-search.Opts
|
||||
---@field scope string|nil The scope of the search
|
||||
---@field json boolean|nil Whather to request JSON enocded results
|
||||
|
||||
---Build a Hoogle request URL
|
||||
---@param search_term string
|
||||
---@param opts TelescopeHoogleWebOpts
|
||||
---@param opts haskell-tools.hoogle.telescope.web.Opts
|
||||
local function mk_hoogle_request(search_term, opts)
|
||||
local hoogle_opts = opts.hoogle or {}
|
||||
local scope_param = hoogle_opts.scope and '&scope=' .. hoogle_opts.scope or ''
|
||||
@ -59,7 +58,7 @@ if deps.has_telescope() then
|
||||
local HoogleHelpers = require('haskell-tools.hoogle.helpers')
|
||||
|
||||
---@param search_term string
|
||||
---@param opts TelescopeHoogleWebOpts|nil
|
||||
---@param opts haskell-tools.hoogle.telescope.web.Opts|nil
|
||||
---@return nil
|
||||
function WebHoogleHandler.telescope_search(search_term, opts)
|
||||
local config = deps.require_telescope('telescope.config').values
|
||||
@ -81,7 +80,7 @@ if deps.has_telescope() then
|
||||
local url = mk_hoogle_request(search_term, opts)
|
||||
local curl_command = { 'curl', '--silent', url, '-H', 'Accept: application/json' }
|
||||
log.debug(curl_command)
|
||||
compat.system(curl_command, nil, function(result)
|
||||
vim.system(curl_command, nil, function(result)
|
||||
---@cast result vim.SystemCompleted
|
||||
log.debug { 'Hoogle web response', result }
|
||||
local response = result.stdout
|
||||
@ -117,7 +116,7 @@ if deps.has_telescope() then
|
||||
end
|
||||
|
||||
---@param search_term string
|
||||
---@param opts TelescopeHoogleWebOpts|nil
|
||||
---@param opts haskell-tools.hoogle.telescope.web.Opts|nil
|
||||
---@return nil
|
||||
function WebHoogleHandler.browser_search(search_term, opts)
|
||||
opts = vim.tbl_deep_extend('keep', opts or {}, {
|
||||
|
||||
@ -39,19 +39,19 @@ end
|
||||
|
||||
---@class HaskellTools
|
||||
local HaskellTools = {
|
||||
---@type HlsTools
|
||||
---@type haskell-tools.Hls
|
||||
lsp = lazy_require('haskell-tools.lsp'),
|
||||
---@type HoogleTools
|
||||
---@type haskell-tools.Hoogle
|
||||
hoogle = lazy_require('haskell-tools.hoogle'),
|
||||
---@type HsReplTools
|
||||
---@type haskell-tools.Repl
|
||||
repl = lazy_require('haskell-tools.repl'),
|
||||
---@type HsProjectTools
|
||||
---@type haskell-tools.Project
|
||||
project = lazy_require('haskell-tools.project'),
|
||||
---@type FastTagsTools
|
||||
---@type haskell-tools.FastTags
|
||||
tags = lazy_require('haskell-tools.tags'),
|
||||
---@type HsDapTools
|
||||
---@type haskell-tools.Dap
|
||||
dap = lazy_require('haskell-tools.dap'),
|
||||
---@type HaskellToolsLog
|
||||
---@type haskell-tools.Log
|
||||
log = lazy_require('haskell-tools.log'),
|
||||
}
|
||||
|
||||
|
||||
@ -10,8 +10,8 @@
|
||||
|
||||
local HTConfig = require('haskell-tools.config.internal')
|
||||
|
||||
---@class InternalApi
|
||||
local InternalApi = {}
|
||||
---@class haskell-tools.internal.Api
|
||||
local Api = {}
|
||||
|
||||
---@return boolean tf Is LSP supported for the current buffer?
|
||||
local function buf_is_lsp_supported()
|
||||
@ -65,15 +65,24 @@ local function dap_discover()
|
||||
elseif type(auto_discover) == 'boolean' then
|
||||
return require('haskell-tools').dap.discover_configurations()
|
||||
end
|
||||
---@cast auto_discover AddDapConfigOpts
|
||||
---@cast auto_discover haskell-tools.dap.AddConfigOpts
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
require('haskell-tools').dap.discover_configurations(bufnr, auto_discover)
|
||||
end
|
||||
|
||||
local function init()
|
||||
if vim.g.haskell_tools_loaded then
|
||||
return
|
||||
end
|
||||
vim.g.haskell_tools_loaded = true
|
||||
require('haskell-tools.commands').init()
|
||||
end
|
||||
|
||||
---ftplugin implementation
|
||||
function InternalApi.ftplugin()
|
||||
function Api.ftplugin()
|
||||
init()
|
||||
start_or_attach()
|
||||
dap_discover()
|
||||
end
|
||||
|
||||
return InternalApi
|
||||
return Api
|
||||
|
||||
@ -3,35 +3,35 @@
|
||||
---@brief [[
|
||||
--- The following commands are available:
|
||||
---
|
||||
--- * `:HtLog` - Open the haskell-tools.nvim log file.
|
||||
--- * `:HlsLog` - Open the haskell-language-server log file.
|
||||
--- * `:HtSetLogLevel` - Set the haskell-tools.nvim and LSP client log level.
|
||||
--- * `:Haskell log setLevel` - Set the haskell-tools.nvim and LSP client log level.
|
||||
--- * `:Haskell log openLog` - Open the haskell-tools.nvim log file.
|
||||
--- * `:Haskell log openHlsLog` - Open the haskell-language-server log file.
|
||||
---@brief ]]
|
||||
|
||||
---@class HaskellToolsLog
|
||||
local HaskellToolsLog = {}
|
||||
---@class haskell-tools.Log
|
||||
local Log = {}
|
||||
|
||||
---Get the haskell-language-server log file
|
||||
---@return string filepath
|
||||
function HaskellToolsLog.get_hls_logfile()
|
||||
function Log.get_hls_logfile()
|
||||
return require('haskell-tools.log.internal').get_hls_logfile()
|
||||
end
|
||||
|
||||
---Get the haskell-tools.nvim log file path.
|
||||
---@return string filepath
|
||||
function HaskellToolsLog.get_logfile()
|
||||
function Log.get_logfile()
|
||||
return require('haskell-tools.log.internal').get_logfile()
|
||||
end
|
||||
|
||||
---Open the haskell-language-server log file
|
||||
---@return nil
|
||||
function HaskellToolsLog.nvim_open_hls_logfile()
|
||||
function Log.nvim_open_hls_logfile()
|
||||
return require('haskell-tools.log.internal').nvim_open_hls_logfile()
|
||||
end
|
||||
|
||||
---Open the haskell-tools.nvim log file.
|
||||
---@return nil
|
||||
function HaskellToolsLog.nvim_open_logfile()
|
||||
function Log.nvim_open_logfile()
|
||||
return require('haskell-tools.log.internal').nvim_open_logfile()
|
||||
end
|
||||
|
||||
@ -39,38 +39,8 @@ end
|
||||
---@param level (string|integer) The log level
|
||||
---@return nil
|
||||
---@see vim.log.levels
|
||||
function HaskellToolsLog.set_level(level)
|
||||
function Log.set_level(level)
|
||||
return require('haskell-tools.log.internal').set_level(level)
|
||||
end
|
||||
|
||||
local commands = {
|
||||
{
|
||||
'HtLog',
|
||||
function()
|
||||
HaskellToolsLog.nvim_open_logfile()
|
||||
end,
|
||||
{},
|
||||
},
|
||||
{
|
||||
'HlsLog',
|
||||
function()
|
||||
HaskellToolsLog.nvim_open_hls_logfile()
|
||||
end,
|
||||
{ nargs = 1 },
|
||||
},
|
||||
{
|
||||
'HtSetLogLevel',
|
||||
function(tbl)
|
||||
local level = vim.fn.expand(tbl.args)
|
||||
---@cast level string
|
||||
HaskellToolsLog.set_level(tonumber(level) or level)
|
||||
end,
|
||||
{ nargs = 1 },
|
||||
},
|
||||
}
|
||||
|
||||
for _, command in ipairs(commands) do
|
||||
vim.api.nvim_create_user_command(unpack(command))
|
||||
end
|
||||
|
||||
return HaskellToolsLog
|
||||
return Log
|
||||
|
||||
@ -8,10 +8,8 @@
|
||||
--- The internal API for use by this plugin's ftplugins
|
||||
---@brief ]]
|
||||
|
||||
local compat = require('haskell-tools.compat')
|
||||
|
||||
---@class HaskellToolsLogInternal
|
||||
local HaskellToolsLogInternal = {
|
||||
---@class haskell-tools.internal.Log
|
||||
local Log = {
|
||||
-- NOTE: These functions are initialised as empty for type checking purposes
|
||||
-- and implemented later.
|
||||
trace = function(_) end,
|
||||
@ -35,13 +33,13 @@ local logfilename = HTConfig.tools.log.logfile
|
||||
|
||||
---Get the haskell-tools.nvim log file path.
|
||||
---@return string filepath
|
||||
function HaskellToolsLogInternal.get_logfile()
|
||||
function Log.get_logfile()
|
||||
return logfilename
|
||||
end
|
||||
|
||||
---Open the haskell-tools.nvim log file.
|
||||
function HaskellToolsLogInternal.nvim_open_logfile()
|
||||
vim.cmd('e ' .. HaskellToolsLogInternal.get_logfile())
|
||||
function Log.nvim_open_logfile()
|
||||
vim.cmd('e ' .. Log.get_logfile())
|
||||
end
|
||||
|
||||
local logfile, openerr
|
||||
@ -64,7 +62,7 @@ local function open_logfile()
|
||||
return false
|
||||
end
|
||||
|
||||
local log_info = compat.uv.fs_stat(logfilename)
|
||||
local log_info = vim.uv.fs_stat(logfilename)
|
||||
if log_info and log_info.size > LARGE then
|
||||
local warn_msg =
|
||||
string.format('haskell-tools.nvim log is large (%d MB): %s', log_info.size / (1000 * 1000), logfilename)
|
||||
@ -81,13 +79,13 @@ local opts = HTConfig.tools.log
|
||||
local hls_log = HTConfig.hls.logfile
|
||||
|
||||
--- Get the haskell-language-server log file
|
||||
function HaskellToolsLogInternal.get_hls_logfile()
|
||||
function Log.get_hls_logfile()
|
||||
return hls_log
|
||||
end
|
||||
|
||||
-- Open the haskell-language-server log file
|
||||
function HaskellToolsLogInternal.nvim_open_hls_logfile()
|
||||
vim.cmd('e ' .. HaskellToolsLogInternal.get_hls_logfile())
|
||||
function Log.nvim_open_hls_logfile()
|
||||
vim.cmd('e ' .. Log.get_hls_logfile())
|
||||
end
|
||||
|
||||
local log_levels = vim.deepcopy(vim.log.levels)
|
||||
@ -98,26 +96,25 @@ end
|
||||
--- Set the log level
|
||||
--- @param level (string|integer) The log level
|
||||
--- @see vim.log.levels
|
||||
function HaskellToolsLogInternal.set_level(level)
|
||||
function Log.set_level(level)
|
||||
if type(level) == 'string' then
|
||||
HaskellToolsLogInternal.level =
|
||||
assert(log_levels[string.upper(level)], string.format('haskell-tools: Invalid log level: %q', level))
|
||||
Log.level = assert(log_levels[string.upper(level)], string.format('haskell-tools: Invalid log level: %q', level))
|
||||
else
|
||||
assert(log_levels[level], string.format('haskell-tools: Invalid log level: %d', level))
|
||||
HaskellToolsLogInternal.level = level
|
||||
Log.level = level
|
||||
end
|
||||
vim.lsp.set_log_level(HaskellToolsLogInternal.level)
|
||||
vim.lsp.set_log_level(Log.level)
|
||||
end
|
||||
|
||||
HaskellToolsLogInternal.set_level(opts.level)
|
||||
Log.set_level(opts.level)
|
||||
|
||||
for level, levelnr in pairs(vim.log.levels) do
|
||||
HaskellToolsLogInternal[level:lower()] = function(...)
|
||||
if HaskellToolsLogInternal.level == vim.log.levels.OFF or not open_logfile() then
|
||||
Log[level:lower()] = function(...)
|
||||
if Log.level == vim.log.levels.OFF or not open_logfile() then
|
||||
return false
|
||||
end
|
||||
local argc = select('#', ...)
|
||||
if levelnr < HaskellToolsLogInternal.level then
|
||||
if levelnr < Log.level then
|
||||
return false
|
||||
end
|
||||
if argc == 0 then
|
||||
@ -143,6 +140,6 @@ for level, levelnr in pairs(vim.log.levels) do
|
||||
end
|
||||
end
|
||||
|
||||
HaskellToolsLogInternal.debug { 'Config', HTConfig }
|
||||
Log.debug { 'Config', HTConfig }
|
||||
|
||||
return HaskellToolsLogInternal
|
||||
return Log
|
||||
|
||||
@ -10,31 +10,30 @@
|
||||
|
||||
local Types = require('haskell-tools.types.internal')
|
||||
|
||||
---@class LspHelpers
|
||||
---@class haskell-tools.lsp.Helpers
|
||||
local LspHelpers = {}
|
||||
|
||||
local compat = require('haskell-tools.compat')
|
||||
LspHelpers.get_clients = compat.get_clients
|
||||
LspHelpers.get_clients = vim.lsp.get_clients
|
||||
|
||||
LspHelpers.haskell_client_name = 'haskell-tools.nvim'
|
||||
LspHelpers.cabal_client_name = 'haskell-tools.nvim (cabal)'
|
||||
|
||||
---@param bufnr number the buffer to get clients for
|
||||
---@return lsp.Client[] haskell_clients
|
||||
---@return vim.lsp.Client[] haskell_clients
|
||||
---@see util.get_clients
|
||||
function LspHelpers.get_active_haskell_clients(bufnr)
|
||||
return LspHelpers.get_clients { bufnr = bufnr, name = LspHelpers.haskell_client_name }
|
||||
end
|
||||
|
||||
---@param bufnr number the buffer to get clients for
|
||||
---@return lsp.Client[] cabal_clinets
|
||||
---@return vim.lsp.Client[] cabal_clinets
|
||||
---@see util.get_clients
|
||||
function LspHelpers.get_active_cabal_clients(bufnr)
|
||||
return LspHelpers.get_clients { bufnr = bufnr, name = LspHelpers.cabal_client_name }
|
||||
end
|
||||
|
||||
---@param bufnr number the buffer to get clients for
|
||||
---@return lsp.Client[] ht_clients The haskell + cabal clients
|
||||
---@return vim.lsp.Client[] ht_clients The haskell + cabal clients
|
||||
---@see util.get_clients
|
||||
---@see util.get_active_haskell_clients
|
||||
---@see util.get_active_cabal_clients
|
||||
|
||||
@ -14,11 +14,11 @@ local HtProjectHelpers = require('haskell-tools.project.helpers')
|
||||
|
||||
local hover = {}
|
||||
|
||||
---@class HtHoverState
|
||||
---@class haskell-tools.hover.State
|
||||
---@field winnr number|nil The hover window number
|
||||
---@field commands (fun():nil)[] List of hover actions
|
||||
|
||||
---@type HtHoverState
|
||||
---@type haskell-tools.hover.State
|
||||
local _state = {
|
||||
winnr = nil,
|
||||
commands = {},
|
||||
|
||||
@ -3,19 +3,18 @@
|
||||
local HTConfig = require('haskell-tools.config.internal')
|
||||
local log = require('haskell-tools.log.internal')
|
||||
local Types = require('haskell-tools.types.internal')
|
||||
local compat = require('haskell-tools.compat')
|
||||
|
||||
---@brief [[
|
||||
--- The following commands are available:
|
||||
---
|
||||
--- * `:HlsStart` - Start the LSP client.
|
||||
--- * `:HlsStop` - Stop the LSP client.
|
||||
--- * `:HlsRestart` - Restart the LSP client.
|
||||
--- * `:HlsEvalAll` - Evaluate all code snippets in comments.
|
||||
--- * `:Hls start` - Start the LSP client.
|
||||
--- * `:Hls stop` - Stop the LSP client.
|
||||
--- * `:Hls restart` - Restart the LSP client.
|
||||
--- * `:Hls evalAll` - Evaluate all code snippets in comments.
|
||||
---@brief ]]
|
||||
|
||||
---To minimise the risk of this occurring, we attempt to shut down hls cleanly before exiting neovim.
|
||||
---@param client lsp.Client The LSP client
|
||||
---@param client vim.lsp.Client The LSP client
|
||||
---@param bufnr number The buffer number
|
||||
---@return nil
|
||||
local function ensure_clean_exit_on_quit(client, bufnr)
|
||||
@ -33,7 +32,7 @@ end
|
||||
---Some plugins that add LSP client capabilities which are not built-in to neovim
|
||||
---(like nvim-ufo and nvim-lsp-selection-range) cause error messages, because
|
||||
---haskell-language-server falsly advertises those server_capabilities for cabal files.
|
||||
---@param client lsp.Client
|
||||
---@param client vim.lsp.Client
|
||||
---@return nil
|
||||
local function fix_cabal_client(client)
|
||||
local LspHelpers = require('haskell-tools.lsp.helpers')
|
||||
@ -47,7 +46,7 @@ local function fix_cabal_client(client)
|
||||
end
|
||||
end
|
||||
|
||||
---@class LoadHlsSettingsOpts
|
||||
---@class haskell-tools.load_hls_settings.Opts
|
||||
---@field settings_file_pattern string|nil File name or pattern to search for. Defaults to 'hls.json'
|
||||
|
||||
log.debug('Setting up the LSP client...')
|
||||
@ -68,22 +67,22 @@ if Types.evaluate(hover_opts.enable) then
|
||||
handlers['textDocument/hover'] = hover.on_hover
|
||||
end
|
||||
|
||||
---@class HlsTools
|
||||
local HlsTools = {}
|
||||
---@class haskell-tools.Hls
|
||||
local Hls = {}
|
||||
---Search the project root for a haskell-language-server settings JSON file and load it to a Lua table.
|
||||
---Falls back to the `hls.default_settings` if no file is found or file cannot be read or decoded.
|
||||
---@param project_root string|nil The project root
|
||||
---@param opts LoadHlsSettingsOpts|nil
|
||||
---@param opts haskell-tools.load_hls_settings.Opts|nil
|
||||
---@return table hls_settings
|
||||
---@see https://haskell-language-server.readthedocs.io/en/latest/configuration.html
|
||||
HlsTools.load_hls_settings = function(project_root, opts)
|
||||
Hls.load_hls_settings = function(project_root, opts)
|
||||
local default_settings = HTConfig.hls.default_settings
|
||||
if not project_root then
|
||||
return default_settings
|
||||
end
|
||||
local default_opts = { settings_file_pattern = 'hls.json' }
|
||||
opts = vim.tbl_deep_extend('force', {}, default_opts, opts or {})
|
||||
local results = vim.fn.glob(compat.joinpath(project_root, opts.settings_file_pattern), true, true)
|
||||
local results = vim.fn.glob(vim.fs.joinpath(project_root, opts.settings_file_pattern), true, true)
|
||||
if #results == 0 then
|
||||
log.info(opts.settings_file_pattern .. ' not found in project root ' .. project_root)
|
||||
return default_settings
|
||||
@ -106,7 +105,7 @@ end
|
||||
---Fails silently if the buffer's filetype is not one of the filetypes specified in the config.
|
||||
---@param bufnr number|nil The buffer number (optional), defaults to the current buffer
|
||||
---@return number|nil client_id The LSP client ID
|
||||
HlsTools.start = function(bufnr)
|
||||
Hls.start = function(bufnr)
|
||||
local ht = require('haskell-tools')
|
||||
bufnr = bufnr or vim.api.nvim_get_current_buf()
|
||||
local file = vim.api.nvim_buf_get_name(bufnr)
|
||||
@ -175,7 +174,7 @@ end
|
||||
---Stop the LSP client.
|
||||
---@param bufnr number|nil The buffer number (optional), defaults to the current buffer
|
||||
---@return table[] clients A list of clients that will be stopped
|
||||
HlsTools.stop = function(bufnr)
|
||||
Hls.stop = function(bufnr)
|
||||
bufnr = bufnr or vim.api.nvim_get_current_buf()
|
||||
local LspHelpers = require('haskell-tools.lsp.helpers')
|
||||
local clients = LspHelpers.get_active_ht_clients(bufnr)
|
||||
@ -187,11 +186,11 @@ end
|
||||
---Fails silently if the buffer's filetype is not one of the filetypes specified in the config.
|
||||
---@param bufnr number|nil The buffer number (optional), defaults to the current buffer
|
||||
---@return number|nil client_id The LSP client ID after restart
|
||||
HlsTools.restart = function(bufnr)
|
||||
Hls.restart = function(bufnr)
|
||||
local lsp = require('haskell-tools').lsp
|
||||
bufnr = bufnr or vim.api.nvim_get_current_buf()
|
||||
local clients = lsp.stop(bufnr)
|
||||
local timer, err_name, err_msg = compat.uv.new_timer()
|
||||
local timer, err_name, err_msg = vim.uv.new_timer()
|
||||
if not timer then
|
||||
log.error { 'Could not create timer', err_name, err_msg }
|
||||
return
|
||||
@ -222,44 +221,47 @@ end
|
||||
---Evaluate all code snippets in comments.
|
||||
---@param bufnr number|nil Defaults to the current buffer.
|
||||
---@return nil
|
||||
HlsTools.buf_eval_all = function(bufnr)
|
||||
Hls.buf_eval_all = function(bufnr)
|
||||
local eval = require('haskell-tools.lsp.eval')
|
||||
return eval.all(bufnr)
|
||||
end
|
||||
|
||||
local commands = {
|
||||
{
|
||||
'HlsStart',
|
||||
function()
|
||||
HlsTools.start()
|
||||
end,
|
||||
{},
|
||||
},
|
||||
{
|
||||
'HlsStop',
|
||||
function()
|
||||
HlsTools.stop()
|
||||
end,
|
||||
{},
|
||||
},
|
||||
{
|
||||
'HlsRestart',
|
||||
function()
|
||||
HlsTools.restart()
|
||||
end,
|
||||
{},
|
||||
},
|
||||
{
|
||||
'HlsEvalAll',
|
||||
function()
|
||||
HlsTools.buf_eval_all()
|
||||
end,
|
||||
{},
|
||||
},
|
||||
---@enum haskell-tools.HlsCmd
|
||||
local HlsCmd = {
|
||||
start = 'start',
|
||||
stop = 'stop',
|
||||
restart = 'restart',
|
||||
evalAll = 'evalAll',
|
||||
}
|
||||
|
||||
for _, command in ipairs(commands) do
|
||||
vim.api.nvim_create_user_command(unpack(command))
|
||||
local function hls_command(opts)
|
||||
local fargs = opts.fargs
|
||||
local cmd = fargs[1] ---@as haskell-tools.HlsCmd
|
||||
if cmd == HlsCmd.start then
|
||||
Hls.start()
|
||||
elseif cmd == HlsCmd.stop then
|
||||
Hls.stop()
|
||||
elseif cmd == HlsCmd.restart then
|
||||
Hls.restart()
|
||||
elseif cmd == HlsCmd.evalAll then
|
||||
Hls.buf_eval_all()
|
||||
end
|
||||
end
|
||||
|
||||
return HlsTools
|
||||
vim.api.nvim_create_user_command('Hls', hls_command, {
|
||||
nargs = '+',
|
||||
desc = 'Commands for interacting with the haskell-language-server LSP client',
|
||||
complete = function(arg_lead, cmdline, _)
|
||||
local clients = require('haskell-tools.lsp.helpers').get_active_haskell_clients(0)
|
||||
---@type haskell-tools.HlsCmd[]
|
||||
local available_commands = #clients == 0 and { 'start' } or { 'stop', 'restart', 'evalAll' }
|
||||
---@type haskell-tools.HlsCmd[]
|
||||
if cmdline:match('^Hls%s+%w*$') then
|
||||
return vim.tbl_filter(function(command)
|
||||
return command:find(arg_lead) ~= nil
|
||||
end, available_commands)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
return Hls
|
||||
|
||||
@ -8,11 +8,9 @@
|
||||
--- Functions for interacting with the operating system
|
||||
---@brief ]]
|
||||
|
||||
local compat = require('haskell-tools.compat')
|
||||
local log = require('haskell-tools.log.internal')
|
||||
local uv = compat.uv
|
||||
|
||||
---@class OS
|
||||
---@class haskell-tools.OS
|
||||
local OS = {}
|
||||
|
||||
---@param url string
|
||||
@ -32,7 +30,7 @@ OS.open_browser = function(url)
|
||||
if browser_cmd and vim.fn.executable(browser_cmd) == 1 then
|
||||
local cmd = { browser_cmd, url }
|
||||
log.debug { 'Opening browser', cmd }
|
||||
compat.system(cmd, nil, function(sc)
|
||||
vim.system(cmd, nil, function(sc)
|
||||
---@cast sc vim.SystemCompleted
|
||||
if sc.code ~= 0 then
|
||||
log.error { 'Error opening browser', sc.code, sc.stderr }
|
||||
@ -63,16 +61,16 @@ end
|
||||
---@return string|nil content
|
||||
---@async
|
||||
OS.read_file_async = function(filename)
|
||||
local file_fd = uv.fs_open(filename, 'r', 438)
|
||||
local file_fd = vim.uv.fs_open(filename, 'r', 438)
|
||||
if not file_fd then
|
||||
return nil
|
||||
end
|
||||
local stat = uv.fs_fstat(file_fd)
|
||||
local stat = vim.uv.fs_fstat(file_fd)
|
||||
if not stat then
|
||||
return nil
|
||||
end
|
||||
local data = uv.fs_read(file_fd, stat.size, 0)
|
||||
uv.fs_close(file_fd)
|
||||
local data = vim.uv.fs_read(file_fd, stat.size, 0)
|
||||
vim.uv.fs_close(file_fd)
|
||||
---@cast data string?
|
||||
return data
|
||||
end
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
--- Parsing functions
|
||||
---@brief ]]
|
||||
|
||||
---@class HtParser
|
||||
---@class haskell-tools.Parser
|
||||
local HtParser = {}
|
||||
|
||||
--- Pretty-print a type signature
|
||||
|
||||
@ -12,27 +12,26 @@ local Strings = require('haskell-tools.strings')
|
||||
local HtParser = require('haskell-tools.parser')
|
||||
local Dap = require('haskell-tools.dap.internal')
|
||||
local OS = require('haskell-tools.os')
|
||||
local compat = require('haskell-tools.compat')
|
||||
|
||||
---@class CabalProjectHelper
|
||||
local CabalProjectHelper = {}
|
||||
---@class haskell-tools.project.cabal.Helper
|
||||
local Helper = {}
|
||||
|
||||
---@class CabalEntryPointParserData
|
||||
---@class haskell-tools.project.cabal.EntryPointParserData
|
||||
---@field idx integer
|
||||
---@field lines string[]
|
||||
---@field line string
|
||||
---@field package_dir string
|
||||
|
||||
---@class CabalEntryPointParserState
|
||||
---@class haskell-tools.project.cabal.EntryPointParserState
|
||||
---@field package_name string
|
||||
---@field entry_points HsEntryPoint[]
|
||||
---@field entry_points haskell-tools.EntryPoint[]
|
||||
---@field mains string[]
|
||||
---@field source_dirs string[]
|
||||
---@field src_dir_indent_pattern string
|
||||
---@field exe_name string | nil
|
||||
|
||||
---@param data CabalEntryPointParserData
|
||||
---@param state CabalEntryPointParserState
|
||||
---@param data haskell-tools.project.cabal.EntryPointParserData
|
||||
---@param state haskell-tools.project.cabal.EntryPointParserState
|
||||
local function get_entrypoint_from_line(data, state)
|
||||
local package_dir = data.package_dir
|
||||
local idx = data.idx
|
||||
@ -78,7 +77,7 @@ end
|
||||
|
||||
---Parse the DAP entry points from a *.cabal file
|
||||
---@param package_file string Path to the *.cabal file
|
||||
---@return HsEntryPoint[] entry_points
|
||||
---@return haskell-tools.EntryPoint[] entry_points
|
||||
---@async
|
||||
local function parse_package_entrypoints(package_file)
|
||||
local state = {
|
||||
@ -96,7 +95,7 @@ local function parse_package_entrypoints(package_file)
|
||||
for idx, line in ipairs(lines) do
|
||||
local is_comment = vim.startswith(Strings.trim(line), '--')
|
||||
if not is_comment then
|
||||
---@type CabalEntryPointParserData
|
||||
---@type haskell-tools.project.cabal.EntryPointParserData
|
||||
local data = {
|
||||
package_dir = package_dir,
|
||||
line = line,
|
||||
@ -111,14 +110,14 @@ end
|
||||
|
||||
---Parse the DAP entry points from a *.cabal file
|
||||
---@param package_path string Path to a package directory
|
||||
---@return HsEntryPoint[] entry_points
|
||||
---@return haskell-tools.EntryPoint[] entry_points
|
||||
---@async
|
||||
function CabalProjectHelper.parse_package_entrypoints(package_path)
|
||||
function Helper.parse_package_entrypoints(package_path)
|
||||
local entry_points = {}
|
||||
for _, package_file in pairs(vim.fn.glob(compat.joinpath(package_path, '*.cabal'), true, true)) do
|
||||
for _, package_file in pairs(vim.fn.glob(vim.fs.joinpath(package_path, '*.cabal'), true, true)) do
|
||||
vim.list_extend(entry_points, parse_package_entrypoints(package_file))
|
||||
end
|
||||
return entry_points
|
||||
end
|
||||
|
||||
return CabalProjectHelper
|
||||
return Helper
|
||||
|
||||
@ -13,9 +13,8 @@ local Strings = require('haskell-tools.strings')
|
||||
local OS = require('haskell-tools.os')
|
||||
local cabal = require('haskell-tools.project.cabal')
|
||||
local stack = require('haskell-tools.project.stack')
|
||||
local compat = require('haskell-tools.compat')
|
||||
|
||||
---@class HtProjectHelpers
|
||||
---@class haskell-tools.project.Helpers
|
||||
local HtProjectHelpers = {}
|
||||
|
||||
---@param path string
|
||||
@ -32,8 +31,8 @@ end
|
||||
---@param ... string Search patterns (can be globs)
|
||||
---@return string|nil The first file that matches the globs
|
||||
local function find_file(path, ...)
|
||||
for _, search_term in ipairs(compat.tbl_flatten { ... }) do
|
||||
local results = vim.fn.glob(compat.joinpath(path, search_term), true, true)
|
||||
for _, search_term in ipairs(vim.iter({ ... }):flatten():totable()) do
|
||||
local results = vim.fn.glob(vim.fs.joinpath(path, search_term), true, true)
|
||||
if #results > 0 then
|
||||
return results[1]
|
||||
end
|
||||
@ -55,7 +54,7 @@ local function iterate_parents(startpath)
|
||||
if not next or vim.fn.isdirectory(next) == 0 or next == path or next == '/nix/store' then
|
||||
return
|
||||
end
|
||||
if compat.uv.fs_realpath(next) then
|
||||
if vim.uv.fs_realpath(next) then
|
||||
return next, startpath
|
||||
end
|
||||
end
|
||||
@ -87,7 +86,7 @@ end
|
||||
---@param ... string Globs to match in the root directory
|
||||
---@return fun(path:string):(string|nil)
|
||||
local function root_pattern(...)
|
||||
local args = compat.tbl_flatten { ... }
|
||||
local args = vim.iter({ ... }):flatten():totable()
|
||||
local function matcher(path)
|
||||
return find_file(path, unpack(args))
|
||||
end
|
||||
@ -147,7 +146,7 @@ function HtProjectHelpers.get_package_cabal(path)
|
||||
return nil
|
||||
end
|
||||
dir = escape_glob_wildcards(dir)
|
||||
for _, pattern in ipairs(vim.fn.glob(compat.joinpath(dir, '*.cabal'), true, true)) do
|
||||
for _, pattern in ipairs(vim.fn.glob(vim.fs.joinpath(dir, '*.cabal'), true, true)) do
|
||||
if pattern then
|
||||
return pattern
|
||||
end
|
||||
@ -209,7 +208,7 @@ function HtProjectHelpers.parse_package_paths(project_file)
|
||||
if packages_start then
|
||||
local trimmed = Strings.trim(line)
|
||||
local pkg_rel_path = trimmed:match('/(.+)')
|
||||
local pkg_path = compat.joinpath(project_dir, pkg_rel_path)
|
||||
local pkg_path = vim.fs.joinpath(project_dir, pkg_rel_path)
|
||||
if vim.fn.isdirectory(pkg_path) == 1 then
|
||||
package_paths[#package_paths + 1] = pkg_path
|
||||
end
|
||||
@ -223,7 +222,7 @@ end
|
||||
|
||||
---Parse the DAP entry points from a *.cabal file
|
||||
---@param package_path string Path to a package directory
|
||||
---@return HsEntryPoint[] entry_points
|
||||
---@return haskell-tools.EntryPoint[] entry_points
|
||||
---@async
|
||||
function HtProjectHelpers.parse_package_entrypoints(package_path)
|
||||
if HtProjectHelpers.is_cabal_project(package_path) then
|
||||
@ -233,18 +232,18 @@ function HtProjectHelpers.parse_package_entrypoints(package_path)
|
||||
end
|
||||
|
||||
---@param project_root string Project root directory
|
||||
---@return HsEntryPoint[]
|
||||
---@return haskell-tools.EntryPoint[]
|
||||
---@async
|
||||
function HtProjectHelpers.parse_project_entrypoints(project_root)
|
||||
local entry_points = {}
|
||||
local project_file = compat.joinpath(project_root, 'cabal.project')
|
||||
local project_file = vim.fs.joinpath(project_root, 'cabal.project')
|
||||
if vim.fn.filereadable(project_file) == 1 then
|
||||
for _, package_path in pairs(HtProjectHelpers.parse_package_paths(project_file)) do
|
||||
vim.list_extend(entry_points, cabal.parse_package_entrypoints(package_path))
|
||||
end
|
||||
return entry_points
|
||||
end
|
||||
project_file = compat.joinpath(project_root, 'stack.yaml')
|
||||
project_file = vim.fs.joinpath(project_root, 'stack.yaml')
|
||||
if vim.fn.filereadable(project_file) == 1 then
|
||||
for _, package_path in pairs(HtProjectHelpers.parse_package_paths(project_file)) do
|
||||
vim.list_extend(entry_points, stack.parse_package_entrypoints(package_path))
|
||||
|
||||
@ -6,9 +6,9 @@ local deps = require('haskell-tools.deps')
|
||||
---@brief [[
|
||||
--- The following commands are available:
|
||||
---
|
||||
--- * `:HsProjectFile` - Open the project file for the current buffer (cabal.project or stack.yaml).
|
||||
--- * `:HsPackageYaml` - Open the package.yaml file for the current buffer.
|
||||
--- * `:HsPackageCabal` - Open the *.cabal file for the current buffer.
|
||||
--- * `:Haskell projectFile` - Open the project file for the current buffer (cabal.project or stack.yaml).
|
||||
--- * `:Haskell packageYaml` - Open the package.yaml file for the current buffer.
|
||||
--- * `:Haskell packageCabal` - Open the *.cabal file for the current buffer.
|
||||
---@brief ]]
|
||||
|
||||
---@param callback fun(opts:table<string,any>):nil
|
||||
@ -56,13 +56,13 @@ local function telescope_package_files(opts)
|
||||
telescope_package_search(t.find_files, opts)
|
||||
end
|
||||
|
||||
---@class HsProjectTools
|
||||
local HsProjectTools = {}
|
||||
---@class haskell-tools.Project
|
||||
local Project = {}
|
||||
|
||||
---Get the project's root directory
|
||||
---@param project_file string The path to a project file
|
||||
---@return string|nil
|
||||
HsProjectTools.root_dir = function(project_file)
|
||||
Project.root_dir = function(project_file)
|
||||
local HtProjectHelpers = require('haskell-tools.project.helpers')
|
||||
return HtProjectHelpers.match_cabal_project_root(project_file)
|
||||
or HtProjectHelpers.match_stack_project_root(project_file)
|
||||
@ -72,7 +72,7 @@ end
|
||||
|
||||
---Open the package.yaml of the package containing the current buffer.
|
||||
---@return nil
|
||||
HsProjectTools.open_package_yaml = function()
|
||||
Project.open_package_yaml = function()
|
||||
local HtProjectHelpers = require('haskell-tools.project.helpers')
|
||||
vim.schedule(function()
|
||||
local file = vim.api.nvim_buf_get_name(0)
|
||||
@ -93,7 +93,7 @@ end
|
||||
|
||||
---Open the *.cabal file of the package containing the current buffer.
|
||||
---@return nil
|
||||
HsProjectTools.open_package_cabal = function()
|
||||
Project.open_package_cabal = function()
|
||||
vim.schedule(function()
|
||||
local HtProjectHelpers = require('haskell-tools.project.helpers')
|
||||
local file = vim.api.nvim_buf_get_name(0)
|
||||
@ -114,7 +114,7 @@ end
|
||||
|
||||
---Open the current buffer's project file (cabal.project or stack.yaml).
|
||||
---@return nil
|
||||
HsProjectTools.open_project_file = function()
|
||||
Project.open_project_file = function()
|
||||
vim.schedule(function()
|
||||
local HtProjectHelpers = require('haskell-tools.project.helpers')
|
||||
local file = vim.api.nvim_buf_get_name(0)
|
||||
@ -138,37 +138,8 @@ HsProjectTools.open_project_file = function()
|
||||
end)
|
||||
end
|
||||
|
||||
HsProjectTools.telescope_package_grep = deps.has('telescope.builtin') and telescope_package_grep or nil
|
||||
Project.telescope_package_grep = deps.has('telescope.builtin') and telescope_package_grep or nil
|
||||
|
||||
HsProjectTools.telescope_package_files = deps.has('telescope.builtin') and telescope_package_files or nil
|
||||
Project.telescope_package_files = deps.has('telescope.builtin') and telescope_package_files or nil
|
||||
|
||||
local commands = {
|
||||
{
|
||||
'HsPackageYaml',
|
||||
function()
|
||||
HsProjectTools.open_package_yaml()
|
||||
end,
|
||||
{},
|
||||
},
|
||||
{
|
||||
'HsPackageCabal',
|
||||
function()
|
||||
HsProjectTools.open_package_cabal()
|
||||
end,
|
||||
{},
|
||||
},
|
||||
{
|
||||
'HsProjectFile',
|
||||
function()
|
||||
HsProjectTools.open_project_file()
|
||||
end,
|
||||
{},
|
||||
},
|
||||
}
|
||||
|
||||
--- Available if nvim-telescope/telescope.nvim is installed.
|
||||
for _, command in ipairs(commands) do
|
||||
vim.api.nvim_create_user_command(unpack(command))
|
||||
end
|
||||
|
||||
return HsProjectTools
|
||||
return Project
|
||||
|
||||
@ -12,10 +12,9 @@ local Strings = require('haskell-tools.strings')
|
||||
local HtParser = require('haskell-tools.parser')
|
||||
local Dap = require('haskell-tools.dap.internal')
|
||||
local OS = require('haskell-tools.os')
|
||||
local compat = require('haskell-tools.compat')
|
||||
|
||||
---@class StackProjectHelper
|
||||
local StackProjectHelper = {}
|
||||
---@class haskell-tools.project.stack.Helper
|
||||
local Helper = {}
|
||||
|
||||
---@param str string
|
||||
---@return boolean is_yaml_comment
|
||||
@ -23,16 +22,16 @@ local function is_yaml_comment(str)
|
||||
return vim.startswith(Strings.trim(str), '#')
|
||||
end
|
||||
|
||||
---@class StackEntryPointParserData
|
||||
---@class haskell-tools.project.stack.EntryPointParserData
|
||||
---@field idx integer
|
||||
---@field lines string[]
|
||||
---@field line string
|
||||
---@field package_dir string
|
||||
---@field next_line string|nil
|
||||
|
||||
---@class StackEntryPointParserState
|
||||
---@class haskell-tools.project.stack.EntryPointParserState
|
||||
---@field package_name string
|
||||
---@field entry_points HsEntryPoint[]
|
||||
---@field entry_points haskell-tools.EntryPoint[]
|
||||
---@field mains string[]
|
||||
---@field source_dirs string[]
|
||||
---@field parsing_exe_list boolean
|
||||
@ -41,8 +40,8 @@ end
|
||||
---@field exe_indent integer | nil
|
||||
---@field exe_name string | nil
|
||||
|
||||
---@param data StackEntryPointParserData
|
||||
---@param state StackEntryPointParserState
|
||||
---@param data haskell-tools.project.stack.EntryPointParserData
|
||||
---@param state haskell-tools.project.stack.EntryPointParserState
|
||||
local function parse_exe_list_line(data, state)
|
||||
local package_dir = data.package_dir
|
||||
local idx = data.idx
|
||||
@ -92,8 +91,8 @@ local function parse_exe_list_line(data, state)
|
||||
end
|
||||
end
|
||||
|
||||
---@param data StackEntryPointParserData
|
||||
---@param state StackEntryPointParserState
|
||||
---@param data haskell-tools.project.stack.EntryPointParserData
|
||||
---@param state haskell-tools.project.stack.EntryPointParserState
|
||||
local function get_entrypoint_from_line(data, state)
|
||||
local line = data.line
|
||||
state.package_name = state.package_name or line:match('^name:%s*(.+)')
|
||||
@ -109,7 +108,7 @@ end
|
||||
|
||||
---Parse the DAP entry points from a *.cabal file
|
||||
---@param package_file string Path to the *.cabal file
|
||||
---@return HsEntryPoint[] entry_points
|
||||
---@return haskell-tools.EntryPoint[] entry_points
|
||||
---@async
|
||||
local function parse_package_entrypoints(package_file)
|
||||
local state = {
|
||||
@ -128,7 +127,7 @@ local function parse_package_entrypoints(package_file)
|
||||
local lines = vim.split(content, '\n') or {}
|
||||
for idx, line in ipairs(lines) do
|
||||
if not is_yaml_comment(line) then
|
||||
---@type StackEntryPointParserData
|
||||
---@type haskell-tools.project.stack.EntryPointParserData
|
||||
local data = {
|
||||
package_dir = package_dir,
|
||||
line = line,
|
||||
@ -146,14 +145,14 @@ end
|
||||
|
||||
---Parse the DAP entry points from a package.yaml file
|
||||
---@param package_path string Path to a package directory
|
||||
---@return HsEntryPoint[] entry_points
|
||||
---@return haskell-tools.EntryPoint[] entry_points
|
||||
---@async
|
||||
function StackProjectHelper.parse_package_entrypoints(package_path)
|
||||
function Helper.parse_package_entrypoints(package_path)
|
||||
local entry_points = {}
|
||||
for _, package_file in pairs(vim.fn.glob(compat.joinpath(package_path, 'package.yaml'), true, true)) do
|
||||
for _, package_file in pairs(vim.fn.glob(vim.fs.joinpath(package_path, 'package.yaml'), true, true)) do
|
||||
vim.list_extend(entry_points, parse_package_entrypoints(package_file))
|
||||
end
|
||||
return entry_points
|
||||
end
|
||||
|
||||
return StackProjectHelper
|
||||
return Helper
|
||||
|
||||
@ -10,24 +10,24 @@
|
||||
|
||||
local log = require('haskell-tools.log.internal')
|
||||
|
||||
---@class BuiltinRepl
|
||||
---@class haskell-tools.repl.builtin
|
||||
---@field bufnr number
|
||||
---@field job_id number
|
||||
---@field cmd string[]
|
||||
|
||||
---@type BuiltinRepl | nil
|
||||
---@type haskell-tools.repl.builtin | nil
|
||||
local BuiltinRepl = nil
|
||||
|
||||
local function is_repl_loaded()
|
||||
return BuiltinRepl ~= nil and vim.api.nvim_buf_is_loaded(BuiltinRepl.bufnr)
|
||||
end
|
||||
|
||||
---@param callback fun(repl:BuiltinRepl)
|
||||
---@param callback fun(repl:haskell-tools.repl.builtin)
|
||||
---@return nil
|
||||
local function when_repl_loaded(callback)
|
||||
if is_repl_loaded() then
|
||||
local repl = BuiltinRepl
|
||||
---@cast repl BuiltinRepl
|
||||
---@cast repl haskell-tools.repl.builtin
|
||||
callback(repl)
|
||||
end
|
||||
end
|
||||
@ -40,7 +40,7 @@ end
|
||||
---Creates a repl on buffer with id `bufnr`.
|
||||
---@param bufnr number Buffer to be used.
|
||||
---@param cmd string[] command to start the repl
|
||||
---@param opts ReplViewOpts?
|
||||
---@param opts haskell-tools.repl.view.Opts?
|
||||
---@return nil
|
||||
local function buf_create_repl(bufnr, cmd, opts)
|
||||
vim.api.nvim_win_set_buf(0, bufnr)
|
||||
@ -114,16 +114,16 @@ local function create_tab(_)
|
||||
end
|
||||
|
||||
---@param mk_repl_cmd fun(string):(string[]?)
|
||||
---@param options ReplConfig
|
||||
---@return ReplHandlerImpl handler
|
||||
---@param options haskell-tools.repl.Config
|
||||
---@return haskell-tools.repl.impl.Handler handler
|
||||
return function(mk_repl_cmd, options)
|
||||
---@class ReplHandlerImpl
|
||||
local ReplHandlerImpl = {}
|
||||
---@class haskell-tools.repl.impl.Handler
|
||||
local Handler = {}
|
||||
|
||||
---Create a new repl (or toggle its visibility)
|
||||
---@param create_win function|number Function for creating the window or an existing window number
|
||||
---@param mk_cmd fun():string[] Function for creating the repl command
|
||||
---@param opts ReplViewOpts?
|
||||
---@param opts haskell-tools.repl.view.Opts?
|
||||
---@return nil
|
||||
local function create_or_toggle(create_win, mk_cmd, opts)
|
||||
local cmd = mk_cmd()
|
||||
@ -135,11 +135,11 @@ return function(mk_repl_cmd, options)
|
||||
end
|
||||
if is_new_cmd(cmd) then
|
||||
log.debug { 'repl.builtin: New command', cmd }
|
||||
ReplHandlerImpl.quit()
|
||||
Handler.quit()
|
||||
end
|
||||
if is_repl_loaded() then
|
||||
local repl = BuiltinRepl
|
||||
---@cast repl BuiltinRepl
|
||||
---@cast repl haskell-tools.repl.builtin
|
||||
log.debug('repl.builtin: is loaded')
|
||||
local winid = vim.fn.bufwinid(repl.bufnr)
|
||||
if winid ~= -1 then
|
||||
@ -169,10 +169,10 @@ return function(mk_repl_cmd, options)
|
||||
buf_create_repl(bufnr, cmd, opts)
|
||||
end
|
||||
|
||||
---@type ReplView
|
||||
---@type haskell-tools.repl.View
|
||||
local ReplView = {
|
||||
---Create a new repl in a horizontal split
|
||||
---@param opts ReplViewOpts?
|
||||
---@param opts haskell-tools.repl.view.Opts?
|
||||
---@return fun(mk_cmd_fun) create_repl
|
||||
create_repl_split = function(opts)
|
||||
return function(mk_cmd)
|
||||
@ -181,7 +181,7 @@ return function(mk_repl_cmd, options)
|
||||
end,
|
||||
|
||||
---Create a new repl in a vertical split
|
||||
---@param opts ReplViewOpts?
|
||||
---@param opts haskell-tools.repl.view.Opts?
|
||||
---@return fun(function) create_repl
|
||||
create_repl_vsplit = function(opts)
|
||||
return function(mk_cmd)
|
||||
@ -190,7 +190,7 @@ return function(mk_repl_cmd, options)
|
||||
end,
|
||||
|
||||
---Create a new repl in a new tab
|
||||
---@param opts ReplViewOpts?
|
||||
---@param opts haskell-tools.repl.view.Opts?
|
||||
---@return fun(function) create_repl
|
||||
create_repl_tabnew = function(opts)
|
||||
return function(mk_cmd)
|
||||
@ -199,7 +199,7 @@ return function(mk_repl_cmd, options)
|
||||
end,
|
||||
|
||||
---Create a new repl in the current window
|
||||
---@param opts ReplViewOpts?
|
||||
---@param opts haskell-tools.repl.view.Opts?
|
||||
---@return fun(function) create_repl
|
||||
create_repl_cur_win = function(opts)
|
||||
return function(mk_cmd)
|
||||
@ -210,11 +210,11 @@ return function(mk_repl_cmd, options)
|
||||
|
||||
log.debug { 'repl.builtin setup', options }
|
||||
---@private
|
||||
ReplHandlerImpl.go_back = options.auto_focus ~= true
|
||||
Handler.go_back = options.auto_focus ~= true
|
||||
|
||||
---@param filepath string path of the file to load into the repl
|
||||
---@param _ table?
|
||||
function ReplHandlerImpl.toggle(filepath, _)
|
||||
function Handler.toggle(filepath, _)
|
||||
local cur_win = vim.api.nvim_get_current_win()
|
||||
if filepath and not vim.endswith(filepath, '.hs') then
|
||||
local err_msg = 'haskell-tools.repl.builtin: Not a Haskell file: ' .. filepath
|
||||
@ -230,19 +230,19 @@ return function(mk_repl_cmd, options)
|
||||
|
||||
local create_or_toggle_callback = options.builtin.create_repl_window(ReplView)
|
||||
create_or_toggle_callback(mk_repl_cmd_wrapped)
|
||||
if cur_win ~= -1 and ReplHandlerImpl.go_back then
|
||||
if cur_win ~= -1 and Handler.go_back then
|
||||
vim.api.nvim_set_current_win(cur_win)
|
||||
else
|
||||
vim.cmd('startinsert')
|
||||
vim.cmd.startinsert()
|
||||
end
|
||||
end
|
||||
|
||||
---Quit the repl
|
||||
---@return nil
|
||||
function ReplHandlerImpl.quit()
|
||||
function Handler.quit()
|
||||
when_repl_loaded(function(repl)
|
||||
log.debug('repl.builtin: sending quit to repl.')
|
||||
local success, result = pcall(ReplHandlerImpl.send_cmd, ':q')
|
||||
local success, result = pcall(Handler.send_cmd, ':q')
|
||||
if not success then
|
||||
log.warn { 'repl.builtin: Could not send quit command', result }
|
||||
end
|
||||
@ -257,7 +257,7 @@ return function(mk_repl_cmd, options)
|
||||
---Send a command to the repl, followed by <cr>
|
||||
---@param txt string The text to send
|
||||
---@return nil
|
||||
function ReplHandlerImpl.send_cmd(txt)
|
||||
function Handler.send_cmd(txt)
|
||||
when_repl_loaded(function(repl)
|
||||
local cr = '\13'
|
||||
local repl_winid = vim.fn.bufwinid(repl.bufnr)
|
||||
@ -269,11 +269,11 @@ return function(mk_repl_cmd, options)
|
||||
repl_set_cursor()
|
||||
vim.api.nvim_chan_send(repl.job_id, txt .. cr)
|
||||
repl_set_cursor()
|
||||
if not ReplHandlerImpl.go_back and repl_winid ~= nil then
|
||||
if not Handler.go_back and repl_winid ~= nil then
|
||||
vim.api.nvim_set_current_win(repl_winid)
|
||||
vim.cmd('startinsert')
|
||||
end
|
||||
end)
|
||||
end
|
||||
return ReplHandlerImpl
|
||||
return Handler
|
||||
end
|
||||
|
||||
@ -7,15 +7,18 @@
|
||||
---@brief [[
|
||||
--- The following commands are available:
|
||||
---
|
||||
--- * `:HtReplToggle` - Toggle a GHCi repl.
|
||||
--- * `:HtReplQuit` - Quit the current repl.
|
||||
--- * `:HtReplLoad` - Load a Haskell file into the repl.
|
||||
--- * `:HtReplReload` - Reload the current repl.
|
||||
--- * `:Haskell repl toggle {file?}` - Toggle a GHCi repl.
|
||||
--- * `:Haskell repl quit` - Quit the current repl.
|
||||
--- * `:Haskell repl load {file?}` - Load a Haskell file into the repl.
|
||||
--- * `:Haskell repl reload` - Reload the current repl.
|
||||
--- * `:Haskell repl paste_type {register?}` - Query the repl for the type of |registers| {register}
|
||||
--- * `:Haskell repl cword_type` - Query the repl for the type of |cword|
|
||||
--- * `:Haskell repl paste_info {register?}` - Query the repl for the info on |registers| {register}
|
||||
--- * `:Haskell repl cword_info` - Query the repl for info on |cword|
|
||||
---@brief ]]
|
||||
|
||||
local log = require('haskell-tools.log.internal')
|
||||
local Types = require('haskell-tools.types.internal')
|
||||
local compat = require('haskell-tools.compat')
|
||||
|
||||
---Extend a repl command for `file`.
|
||||
---If `file` is `nil`, create a repl the nearest package.
|
||||
@ -99,7 +102,7 @@ local function mk_repl_cmd(file)
|
||||
return mk_stack_repl_cmd(file)
|
||||
end
|
||||
if vim.fn.executable('ghci') == 1 then
|
||||
local cmd = compat.tbl_flatten { 'ghci', file and { file } or {} }
|
||||
local cmd = vim.iter({ 'ghci', file and { file } or {} }):flatten():totable()
|
||||
log.debug { 'mk_repl_cmd', cmd }
|
||||
return cmd
|
||||
end
|
||||
@ -111,11 +114,11 @@ end
|
||||
|
||||
local HTConfig = require('haskell-tools.config.internal')
|
||||
local opts = HTConfig.tools.repl
|
||||
---@type ReplHandlerImpl
|
||||
---@type haskell-tools.repl.impl.Handler
|
||||
local handler
|
||||
|
||||
local handler_type = Types.evaluate(opts.handler)
|
||||
---@cast handler_type ReplHandler
|
||||
---@cast handler_type haskell-tools.repl.Handler
|
||||
if handler_type == 'toggleterm' then
|
||||
log.info('handler = toggleterm')
|
||||
handler = require('haskell-tools.repl.toggleterm')(mk_repl_cmd, opts)
|
||||
@ -155,30 +158,30 @@ local function repl_send_lines(lines)
|
||||
end
|
||||
end
|
||||
|
||||
---@class HsReplTools
|
||||
local HsReplTools = {}
|
||||
---@class haskell-tools.Repl
|
||||
local Repl = {}
|
||||
|
||||
HsReplTools.mk_repl_cmd = mk_repl_cmd
|
||||
Repl.mk_repl_cmd = mk_repl_cmd
|
||||
|
||||
---Create the command to create a repl for the current buffer.
|
||||
---@return table|nil command
|
||||
HsReplTools.buf_mk_repl_cmd = function()
|
||||
Repl.buf_mk_repl_cmd = function()
|
||||
local file = vim.api.nvim_buf_get_name(0)
|
||||
return mk_repl_cmd(file)
|
||||
end
|
||||
|
||||
---Toggle a GHCi REPL
|
||||
HsReplTools.toggle = handler.toggle
|
||||
Repl.toggle = handler.toggle
|
||||
|
||||
---Quit the REPL
|
||||
HsReplTools.quit = handler.quit
|
||||
Repl.quit = handler.quit
|
||||
|
||||
---Can be used to send text objects to the repl.
|
||||
---@usage [[
|
||||
---vim.keymap.set('n', 'ghc', ht.repl.operator, {noremap = true})
|
||||
---@usage ]]
|
||||
---@see operatorfunc
|
||||
HsReplTools.operator = function()
|
||||
Repl.operator = function()
|
||||
local old_operator_func = vim.go.operatorfunc
|
||||
_G.op_func_send_to_repl = function()
|
||||
local start = vim.api.nvim_buf_get_mark(0, '[')
|
||||
@ -194,7 +197,7 @@ end
|
||||
|
||||
---Paste from register `reg` to the REPL
|
||||
---@param reg string|nil register (defaults to '"')
|
||||
HsReplTools.paste = function(reg)
|
||||
Repl.paste = function(reg)
|
||||
local data = vim.fn.getreg(reg or '"')
|
||||
---@cast data string
|
||||
if vim.endswith(data, '\n') then
|
||||
@ -209,29 +212,29 @@ end
|
||||
|
||||
---Query the REPL for the type of register `reg`
|
||||
---@param reg string|nil register (defaults to '"')
|
||||
HsReplTools.paste_type = function(reg)
|
||||
Repl.paste_type = function(reg)
|
||||
handle_reg(':t', reg)
|
||||
end
|
||||
|
||||
---Query the REPL for the type of word under the cursor
|
||||
HsReplTools.cword_type = function()
|
||||
Repl.cword_type = function()
|
||||
handle_cword(':t')
|
||||
end
|
||||
|
||||
---Query the REPL for info on register `reg`
|
||||
---@param reg string|nil register (defaults to '"')
|
||||
HsReplTools.paste_info = function(reg)
|
||||
Repl.paste_info = function(reg)
|
||||
handle_reg(':i', reg)
|
||||
end
|
||||
|
||||
---Query the REPL for the type of word under the cursor
|
||||
HsReplTools.cword_info = function()
|
||||
Repl.cword_info = function()
|
||||
handle_cword(':i')
|
||||
end
|
||||
|
||||
---Load a file into the REPL
|
||||
---@param filepath string The absolute file path
|
||||
HsReplTools.load_file = function(filepath)
|
||||
Repl.load_file = function(filepath)
|
||||
if vim.fn.filereadable(filepath) == 0 then
|
||||
local err_msg = 'File: ' .. filepath .. ' does not exist or is not readable.'
|
||||
log.error(err_msg)
|
||||
@ -241,51 +244,10 @@ HsReplTools.load_file = function(filepath)
|
||||
end
|
||||
|
||||
---Reload the repl
|
||||
HsReplTools.reload = function()
|
||||
Repl.reload = function()
|
||||
handler.send_cmd(':r')
|
||||
end
|
||||
|
||||
vim.keymap.set('n', 'ghc', HsReplTools.operator, { noremap = true })
|
||||
vim.keymap.set('n', 'ghc', Repl.operator, { noremap = true })
|
||||
|
||||
local commands = {
|
||||
{
|
||||
'HtReplToggle',
|
||||
---@param tbl table
|
||||
function(tbl)
|
||||
local filepath = tbl.args ~= '' and vim.fn.expand(tbl.args)
|
||||
---@cast filepath string
|
||||
HsReplTools.toggle(filepath)
|
||||
end,
|
||||
{ nargs = '?' },
|
||||
},
|
||||
{
|
||||
'HtReplLoad',
|
||||
---@param tbl table
|
||||
function(tbl)
|
||||
local filepath = vim.fn.expand(tbl.args)
|
||||
---@cast filepath string
|
||||
HsReplTools.load_file(filepath)
|
||||
end,
|
||||
{ nargs = 1 },
|
||||
},
|
||||
{
|
||||
'HtReplQuit',
|
||||
function()
|
||||
HsReplTools.quit()
|
||||
end,
|
||||
{},
|
||||
},
|
||||
{
|
||||
'HtReplReload',
|
||||
function()
|
||||
HsReplTools.reload()
|
||||
end,
|
||||
{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, command in ipairs(commands) do
|
||||
vim.api.nvim_create_user_command(unpack(command))
|
||||
end
|
||||
|
||||
return HsReplTools
|
||||
return Repl
|
||||
|
||||
@ -27,8 +27,8 @@ local function quote(str)
|
||||
end
|
||||
|
||||
---@param mk_repl_cmd fun(string?):string[]? Function for building the repl that takes an optional file path
|
||||
---@param opts ReplConfig
|
||||
---@return ReplHandlerImpl
|
||||
---@param opts haskell-tools.repl.Config
|
||||
---@return haskell-tools.repl.impl.Handler
|
||||
return function(mk_repl_cmd, opts)
|
||||
local ReplHandlerImpl = {
|
||||
---@private
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
--- Helper functions for working with strings
|
||||
---@brief ]]
|
||||
|
||||
---@class StringsUtil
|
||||
---@class haskell-tools.Strings
|
||||
local Strings = {}
|
||||
|
||||
---Trim leading and trailing whitespace.
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
local HTConfig = require('haskell-tools.config.internal')
|
||||
local Types = require('haskell-tools.types.internal')
|
||||
local log = require('haskell-tools.log.internal')
|
||||
local compat = require('haskell-tools.compat')
|
||||
|
||||
local _state = {
|
||||
fast_tags_generating = false,
|
||||
@ -13,17 +12,17 @@ local _state = {
|
||||
log.debug('Setting up fast-tags tools')
|
||||
local config = HTConfig.tools.tags
|
||||
|
||||
---@class GenerateProjectTagsOpts
|
||||
---@class haskell-tools.tags.generate_project_tags.Opts
|
||||
---@field refresh boolean Whether to refresh the tags if they have already been generated
|
||||
--- for the project (default: true)
|
||||
|
||||
---@class FastTagsTools
|
||||
local FastTagsTools = {}
|
||||
---@class haskell-tools.FastTags
|
||||
local FastTags = {}
|
||||
|
||||
---Generates tags for the current project
|
||||
---@param path string|nil File path
|
||||
---@param opts GenerateProjectTagsOpts|nil Options
|
||||
FastTagsTools.generate_project_tags = function(path, opts)
|
||||
---@param opts haskell-tools.tags.generate_project_tags.Opts|nil Options
|
||||
FastTags.generate_project_tags = function(path, opts)
|
||||
path = path or vim.api.nvim_buf_get_name(0)
|
||||
opts = vim.tbl_extend('force', { refresh = true }, opts or {})
|
||||
local HtProjectHelpers = require('haskell-tools.project.helpers')
|
||||
@ -40,7 +39,7 @@ FastTagsTools.generate_project_tags = function(path, opts)
|
||||
_state.fast_tags_generating = true
|
||||
if project_root then
|
||||
log.debug('Generating project tags for' .. project_root)
|
||||
compat.system({ 'fast-tags', '-R', project_root }, nil, function(sc)
|
||||
vim.system({ 'fast-tags', '-R', project_root }, nil, function(sc)
|
||||
if sc.code ~= 0 then
|
||||
log.error { 'Error running fast-tags on project root', sc.code, sc.stderr }
|
||||
end
|
||||
@ -52,7 +51,7 @@ end
|
||||
|
||||
---Generate tags for the package containing `path`
|
||||
---@param path string|nil File path
|
||||
FastTagsTools.generate_package_tags = function(path)
|
||||
FastTags.generate_package_tags = function(path)
|
||||
path = path or vim.api.nvim_buf_get_name(0)
|
||||
_state.fast_tags_generating = true
|
||||
local HtProjectHelpers = require('haskell-tools.project.helpers')
|
||||
@ -71,7 +70,7 @@ FastTagsTools.generate_package_tags = function(path)
|
||||
log.warn('generate_package_tags: No project root found.')
|
||||
return
|
||||
end
|
||||
compat.system({ 'fast-tags', '-R', package_root, project_root }, nil, function(sc)
|
||||
vim.system({ 'fast-tags', '-R', package_root, project_root }, nil, function(sc)
|
||||
---@cast sc vim.SystemCompleted
|
||||
if sc.code ~= 0 then
|
||||
log.error { 'Error running fast-tags on package', sc.code, sc.stderr }
|
||||
@ -99,9 +98,9 @@ if #package_events > 0 then
|
||||
if _state.fast_tags_generating then
|
||||
return
|
||||
end
|
||||
FastTagsTools.generate_package_tags(meta.file)
|
||||
FastTags.generate_package_tags(meta.file)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return FastTagsTools
|
||||
return FastTags
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
--- Type definitions
|
||||
---@brief ]]
|
||||
|
||||
---@class HsEntryPoint
|
||||
---@class haskell-tools.EntryPoint
|
||||
---@field package_dir string
|
||||
---@field package_name string
|
||||
---@field exe_name string
|
||||
|
||||
Reference in New Issue
Block a user