├── lua
└── penvim
│ ├── funcs
│ ├── init.lua
│ ├── string.lua
│ ├── table.lua
│ └── filedir.lua
│ ├── langs
│ ├── init.lua
│ └── languages
│ │ ├── lua.lua
│ │ └── frameworks
│ │ └── react.lua
│ ├── rooter
│ └── init.lua
│ ├── project_env
│ └── init.lua
│ ├── indentor
│ └── init.lua
│ └── init.lua
├── LICENSE
└── README.md
/lua/penvim/funcs/init.lua:
--------------------------------------------------------------------------------
1 |
2 | local M={}
3 |
4 |
5 | M.filedir = require("penvim.funcs.filedir")
6 | M.string = require("penvim.funcs.string")
7 | M.table = require("penvim.funcs.table")
8 |
9 |
10 | return M
11 |
12 |
--------------------------------------------------------------------------------
/lua/penvim/funcs/string.lua:
--------------------------------------------------------------------------------
1 |
2 | local M = {}
3 |
4 |
5 | function M.split(inputstr, sep)
6 | -- https://stackoverflow.com/a/7615129
7 | if sep == nil then sep = "%s" end
8 | local t={}
9 | for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
10 | table.insert(t, str)
11 | end
12 | return t
13 | end
14 |
15 |
16 | return M
17 |
--------------------------------------------------------------------------------
/lua/penvim/langs/init.lua:
--------------------------------------------------------------------------------
1 |
2 | local M={}
3 | local filetype = vim.bo.filetype
4 |
5 |
6 | function M.load_langs()
7 | if filetype == "lua" then
8 | require('penvim/langs/languages/lua') -- LUA
9 | else
10 | if filetype == "javascriptreact" or filetype == "typescriptreact" then
11 | require('penvim/langs/languages/lua/frameworks/react') -- REACT
12 | end
13 | end
14 | end
15 |
16 |
17 | return M
18 |
19 |
--------------------------------------------------------------------------------
/lua/penvim/langs/languages/lua.lua:
--------------------------------------------------------------------------------
1 |
2 |
3 | vim.opt.softtabstop = 4
4 | vim.opt.shiftwidth = 4 -- spaces per tab (when shifting), when using the >> or << commands, shift lines by 4 spaces
5 | vim.opt.tabstop = 4 -- spaces per tab
6 | vim.opt.smarttab = true -- / indent/dedent in leading whitespace
7 | vim.opt.autoindent = true -- maintain indent of current line
8 | vim.opt.expandtab = false -- don't expand tabs into spaces
9 |
10 |
--------------------------------------------------------------------------------
/lua/penvim/langs/languages/frameworks/react.lua:
--------------------------------------------------------------------------------
1 |
2 | vim.opt.softtabstop = 2
3 | vim.opt.shiftwidth = 2 -- spaces per tab (when shifting), when using the >> or << commands, shift lines by 4 spaces
4 | vim.opt.tabstop = 2 -- spaces per tab
5 | vim.opt.expandtab = true -- expand tabs into spaces
6 |
7 | -- set filetype to typescriptreact if document if javascriptreact
8 | if vim.bo.filetype == "javascriptreact" then
9 | vim.api.nvim_command("set filetype=typescriptreact")
10 | end
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Ali Shahid
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lua/penvim/rooter/init.lua:
--------------------------------------------------------------------------------
1 |
2 | local M={}
3 | local funcs = require("penvim.funcs.filedir")
4 |
5 |
6 | function M.load_rooter()
7 | local current_file_dir = vim.fn.expand('%:p:h')
8 | if not funcs.file_exists(current_file_dir) then
9 | return
10 | end
11 | local current_file_dir_init = current_file_dir
12 | local splited_dir = funcs.dirsplit(current_file_dir)
13 | local patterns = vim.g.penvim_rooter_patterns
14 | local possible_dirs = {current_file_dir.."/"}
15 | local os_user = funcs.osuser()
16 | local os_home_dir = "/home/" .. os_user .. "/"
17 | local final_dir = os_home_dir
18 | local pattern_exist=false
19 |
20 | for _, dir in ipairs(splited_dir) do
21 | if dir=="home" or dir== os_user then
22 | goto continue
23 | end
24 | current_file_dir = current_file_dir .. "/../"
25 | current_file_dir = funcs.normalize_dir(current_file_dir)
26 | possible_dirs[#possible_dirs+1] = current_file_dir
27 | ::continue::
28 | end
29 |
30 | for _, dir in ipairs(possible_dirs) do
31 | for _, pattern in ipairs(patterns) do
32 | pattern = dir .. pattern
33 | pattern_exist = funcs.file_exists(pattern)
34 | if pattern_exist then
35 | final_dir = dir
36 | goto bottom
37 | end
38 | end
39 | end
40 | ::bottom::
41 | -- change directory to directory of current file if no project detects
42 | if final_dir == os_home_dir then
43 | final_dir = current_file_dir_init
44 | end
45 | vim.api.nvim_set_current_dir(final_dir)
46 | end
47 |
48 | return M
49 |
50 |
--------------------------------------------------------------------------------
/lua/penvim/funcs/table.lua:
--------------------------------------------------------------------------------
1 |
2 | local M = {}
3 |
4 | --[[
5 | Ordered table iterator, allow to iterate on the natural order of the keys of a table.
6 | Author: http://lua-users.org/wiki/SortedIteration
7 | useful link: https://www.hiveworkshop.com/threads/syncedtable.332894/
8 | ]]
9 |
10 | local function __genOrderedIndex( t )
11 | local orderedIndex = {}
12 | for key in pairs(t) do
13 | table.insert( orderedIndex, key )
14 | end
15 | table.sort( orderedIndex )
16 | return orderedIndex
17 | end
18 |
19 | local function orderedNext(t, state)
20 | -- Equivalent of the next function, but returns the keys in the alphabetic
21 | -- order. We use a temporary ordered key table that is stored in the
22 | -- table being iterated.
23 |
24 | local key = nil
25 | --print("orderedNext: state = "..tostring(state) )
26 | if state == nil then
27 | -- the first time, generate the index
28 | t.__orderedIndex = __genOrderedIndex( t )
29 | key = t.__orderedIndex[1]
30 | else
31 | -- fetch the next value
32 | for i = 1 ,#t.__orderedIndex do
33 | if t.__orderedIndex[i] == state then
34 | key = t.__orderedIndex[i+1]
35 | end
36 | end
37 | end
38 |
39 | if key then
40 | return key, t[key]
41 | end
42 |
43 | -- no more value to return, cleanup
44 | t.__orderedIndex = nil
45 | end
46 |
47 | function M.SyncedTable(t)
48 | -- Equivalent of the pairs() function on tables. Allows to iterate
49 | -- in order
50 | return orderedNext, t, nil
51 | end
52 |
53 |
54 | return M
55 |
--------------------------------------------------------------------------------
/lua/penvim/funcs/filedir.lua:
--------------------------------------------------------------------------------
1 |
2 | -- collections of functions that can handle files and directories
3 |
4 | local M={}
5 |
6 |
7 | -- check given path is dir return True else false
8 | function M.is_dir(path)
9 | local file = io.open(path, 'r')
10 | local ok, error, code = file:read(1)
11 | file:close()
12 | return code == 21
13 | end
14 |
15 |
16 | function M.dirsplit(inputstr)
17 | -- https://stackoverflow.com/a/7615129/11812032
18 | local sep = "/"
19 | local t = {}
20 | for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
21 | table.insert(t, str)
22 | end
23 | return t
24 | end
25 |
26 |
27 | -- check if file exist
28 | function M.file_exists(fname)
29 | local f = io.open(fname, "r")
30 | if f ~= nil then
31 | io.close(f)
32 | return true
33 | else
34 | return false
35 | end
36 | end
37 |
38 |
39 | function os.capture(cmd, raw)
40 | -- https://gist.github.com/dukeofgaming/453cf950abd99c3dc8fc
41 | local handle = assert(io.popen(cmd, 'r'))
42 | local output = assert(handle:read('*a'))
43 | handle:close()
44 | if raw then return output end
45 | output = string.gsub(string.gsub(string.gsub(output, '^%s+', ''), '%s+$', ''), '[\n\r]+', ' ')
46 | return output
47 | end
48 |
49 |
50 | function M.osuser()
51 | return os.capture("whoami")
52 | end
53 |
54 |
55 | -- normalize dir
56 | -- /home/user/../user/download/../ --> /home/user
57 | function M.normalize_dir(dir)
58 | local stack = {}
59 | local split_dir = M.dirsplit(dir)
60 | for _, r in ipairs(split_dir) do
61 | table.insert(stack, r)
62 | if r == ".." then
63 | stack = {unpack(stack, 1, #stack-2)}
64 | end
65 | end
66 | local str = ""
67 | for _, i in ipairs(stack) do
68 | str = str .. "/" .. i
69 | end
70 | return str .. "/"
71 | end
72 |
73 |
74 | return M
75 |
76 |
--------------------------------------------------------------------------------
/lua/penvim/project_env/init.lua:
--------------------------------------------------------------------------------
1 |
2 | --[[
3 | create .__nvim__.lua file in your project root directory and
4 | define options/configs in that file.
5 |
6 | 1. check if ~/.__nvim__.lua file exist
7 | if exists: load ~/.__nvim__.lua
8 | 2. check if .__nvim__.lua file exist in the project
9 | if exist: load .__nvim__.lua config
10 | NOTE:
11 | .__nvim__.lua is default config file name and it can be change
12 | with 'vim.g.penvim_project_config' (eg: vim.g.penvim_project_config='config.lua')
13 | ]]
14 |
15 |
16 | local M= {}
17 | local filedir = require("penvim.funcs.filedir")
18 | local str = require("penvim.funcs.string")
19 | local table = require("penvim.funcs.table")
20 | local os_user = filedir.osuser()
21 | local config_name = vim.g.penvim_project_config -- project_env config name
22 | local home_con_file = "/home/"..os_user.."/"..config_name
23 | -- local buff_num = vim.api.nvim_get_current_buf()
24 | local filetype = vim.bo.filetype
25 |
26 |
27 | local function conf_file()
28 | --[[ if .__nvim__.lua file exist, return it with full location else return false ]]
29 |
30 | local conff
31 | local curr_file_dir = vim.fn.expand('%:p:h') .. "/"
32 |
33 | -- if directory is not a child of /home/use_name/ then return home's config file (if exist)
34 | if filedir.dirsplit(curr_file_dir)[2] ~= os_user then
35 | if filedir.file_exists(home_con_file) then
36 | return home_con_file
37 | else
38 | return false
39 | end
40 | end
41 |
42 | for _, _ in ipairs(filedir.dirsplit(curr_file_dir)) do
43 | conff = curr_file_dir .. config_name
44 | if filedir.file_exists(conff) then
45 | return curr_file_dir .. config_name
46 | else
47 | curr_file_dir = filedir.normalize_dir(curr_file_dir.."../")
48 | end
49 | end
50 |
51 | return false
52 | end
53 |
54 |
55 | local function apply_config(config)
56 | for option, value in pairs(config) do
57 | vim.opt[option] = value
58 | end
59 | end
60 |
61 |
62 | local function load_config(config_file)
63 |
64 | local configs = dofile(config_file)
65 |
66 | -- exit if config file is empty
67 | if configs == nil then return end
68 |
69 | for lang, config in table.SyncedTable(configs) do
70 | if lang == "all" then
71 | apply_config(config)
72 |
73 | elseif string.find(lang, "_") then
74 | local langs = str.split(lang, "-")
75 | for _, lan in pairs(langs) do
76 | if lan == filetype then
77 | apply_config(config)
78 | end
79 | end
80 | else
81 | if lang == filetype then
82 | apply_config(config)
83 | end
84 | end
85 | end
86 | end
87 |
88 |
89 | function M.load_project_config()
90 | local config_file = conf_file()
91 |
92 | -- only load config file if config file exist
93 | if config_file then
94 | if config_file == home_con_file then
95 | load_config(home_con_file)
96 | else
97 | if filedir.file_exists(home_con_file) then
98 | load_config(home_con_file)
99 | end
100 | load_config(config_file)
101 | end
102 | end
103 | end
104 |
105 |
106 | return M
107 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
PenVim
4 |
5 |
6 | project's root directory and documents indentation detector with project based config loader
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Docs
17 |
Request-Feature/Issues
18 |
19 |     
20 |
21 |
22 |
23 |
24 |
25 | ## Table Of Contents
26 |
27 | * [About the Project](#about-the-project)
28 | * [Examples](#examples-)
29 | * [Getting Started](#getting-started)
30 | * [Prerequisites](#prerequisites)
31 | * [Installation](#installation)
32 | * [Setup](#setup)
33 | * [License](#license)
34 | * [Acknowledgements](#acknowledgements)
35 |
36 |
37 | ## About The Project
38 |
39 | This plugin (Penvim) has 4 purposes:
40 | 1. change current working directory to project's root directory.
41 | 2. detect indentation of Document (Source Code) and set indentation related config according to detected indentation
42 | 3. load config defined in project's root directory
43 | 4. set options according to Language's Standard Style Guide (not implemented yet...)
44 |
45 |
46 | ## Getting Started
47 | Install PenVim using your favorite package manager.
48 |
49 |
50 | ### Prerequisites
51 | * neovim >= 0.7
52 |
53 |
54 | ### Installation
55 |
56 | using ```vim-plug```
57 | ```lua
58 | Plug 'Abstract-IDE/penvim'
59 | ```
60 | or using packer.nvim
61 | ```lua
62 | use {'Abstract-IDE/penvim'}
63 | ```
64 |
65 |
66 | ## Setup
67 |
68 | ```lua
69 | require("penvim").setup() -- use defaults
70 | ```
71 | #### Full Configuration
72 | ```lua
73 | require("penvim").setup({
74 | rooter = {
75 | enable = true, -- enable/disable rooter
76 | patterns = {'.__nvim__.lua', '.git', 'node_modules'}
77 | },
78 | indentor = {
79 | enable = true, -- enable/disable indentor
80 | indent_length = 4, -- tab indent width
81 | accuracy = 5, -- positive integer. higher the number, the more accurate result (but affects the startup time)
82 | disable_types = {
83 | 'help','dashboard','dashpreview','NvimTree','vista','sagahover', 'terminal',
84 | },
85 | },
86 | project_env = {
87 | enable = true, -- enable/disable project_env
88 | config_name = '.__nvim__.lua' -- config file name
89 | },
90 | })
91 | ```
92 |
93 |
94 | ## Examples :
95 |
96 |
97 | sample, config defined in project's root directory
98 |
99 |
100 | ```lua
101 | -- .__nvim__.lua
102 | return {
103 | -- for all file types
104 | all = {
105 | tabstop = 4, -- spaces per tab
106 | cursorline = true, -- highlight current line
107 | relativenumber = true, -- show relative line number
108 | number = true, -- show line numbers
109 | },
110 |
111 | -- for filetype lua
112 | lua = {
113 | smarttab = true, -- / indent/dedent in leading whitespace
114 | softtabstop = 4,
115 | shiftwidth = 4, -- spaces per tab (when shifting), when using the >> or << commands, shift lines by 4 spaces
116 | },
117 |
118 | -- for filetype python and javascript
119 | py_js = {
120 | tabstop = 4, -- spaces per tab
121 | wrap = false, -- don't automatically wrap on load
122 | }
123 | }
124 | ```
125 |
126 |
127 |
128 | ## To-Do
129 | * testing
130 | * implement to set option according to Language's Standard Style Guide
131 | * optimize code
132 |
133 |
134 | ## License
135 | Distributed under the MIT License. See [LICENSE](https://github.com/shaeinst/penvim/blob/main/LICENSE) for more information.
136 |
137 |
138 | ## Acknowledgements
139 | * for [README](https://readme.shaankhan.dev/)
140 |
141 |
--------------------------------------------------------------------------------
/lua/penvim/indentor/init.lua:
--------------------------------------------------------------------------------
1 |
2 | local M = {}
3 | local g = vim.g
4 | local fn = vim.fn
5 | local api = vim.api
6 | local opt = vim.opt
7 |
8 |
9 | local function whitespace_type(line)
10 |
11 | local whitespace = line:match("^%s*"):len()
12 | if whitespace == 0 then
13 | return { type = "blank", }
14 | end
15 |
16 | local tabspace = line:match("^%\t*"):len()
17 | if tabspace > 0 then
18 | return {
19 | type = "tab",
20 | no_of_tab = tabspace
21 | }
22 | end
23 |
24 | return {
25 | type = "space",
26 | no_of_space = whitespace
27 | }
28 | end
29 |
30 |
31 | local function block_comment(line)
32 | -- function to check if current line is the start of block comment
33 | -- and if yes then return its right pair
34 |
35 | local white_space = " "
36 | ::loop::
37 | local space = line:match("^%"..white_space)
38 | if space == white_space then
39 | white_space = white_space .. " "
40 | goto loop
41 | end
42 |
43 | local c_style = line:match("^/%*") -- /*
44 | local html_style = line:match("^$"
51 | elseif lua_style then return "%]=*%]$"
52 | elseif python_style_double then return "\"%\"%\"$"
53 | elseif python_style_single then return "\'%\'%\'$"
54 | else return nil
55 | end
56 | end
57 |
58 |
59 | local function match_pattern(line, pattern)
60 | return line:match(pattern)
61 | end
62 |
63 |
64 | function M.load_indentor()
65 |
66 | local buffer_num = api.nvim_get_current_buf() -- current buffer number
67 | local loc = api.nvim_buf_line_count(buffer_num) -- total lines of code in current file
68 | local current_line_num = 1
69 | local current_line_content, whitespace, whitespace_t
70 | local stack_tab = 0
71 | local stack_space = 0
72 | local space_list = {}
73 | local accuracy = g.penvim_indentor_accuracy
74 |
75 | if loc == 1 then
76 | goto loop_end
77 | end
78 |
79 | ::loop_continue::
80 |
81 | if current_line_num > loc or stack_space > accuracy or stack_tab > accuracy then
82 | goto loop_end
83 | end
84 |
85 | current_line_content = fn.getline(current_line_num)
86 |
87 | -----------------------------------------------
88 | -- operations for BLOCK COMMENT
89 | -----------------------------------------------
90 | Block_comment = block_comment(current_line_content)
91 |
92 | -- if line is not a block comment, handle the operation to the whitespace
93 | if not Block_comment then
94 | goto whitespace
95 | end
96 |
97 | -- any block comment on same line have length of > 3 means bolck comment doesn't exist on same line
98 | if #current_line_content < 4 then
99 | goto loop_block
100 | end
101 | -- check if block comment exist on same single line
102 | if match_pattern(current_line_content, Block_comment) then
103 | current_line_num = current_line_num + 1
104 | goto loop_continue
105 | end
106 |
107 | ::loop_block::
108 | -- if Block Comment, then operate until Right pair of comment is found
109 | if Block_comment then
110 | for _=current_line_num, loc do
111 | current_line_num = current_line_num + 1
112 | current_line_content = fn.getline(current_line_num)
113 | if match_pattern(current_line_content, Block_comment) then
114 | current_line_num = current_line_num + 1
115 | goto loop_continue
116 | end
117 | end
118 | end
119 | -----------------------------------------------
120 |
121 | -----------------------------------------------
122 | -- operations for WHITESPACE
123 | -----------------------------------------------
124 | ::whitespace::
125 | whitespace = whitespace_type(current_line_content)
126 | whitespace_t = whitespace['type']
127 |
128 | if whitespace_t == "blank" then
129 | current_line_num = current_line_num + 1
130 | goto loop_continue
131 | end
132 | if whitespace_t == "tab" then
133 | stack_tab = stack_tab + 1
134 | current_line_num = current_line_num + 1
135 | goto loop_continue
136 | end
137 | if whitespace_t == "space" then
138 | stack_space = stack_space + 1
139 | space_list[#space_list+1] = whitespace.no_of_space
140 | current_line_num = current_line_num + 1
141 | goto loop_continue
142 | end
143 | -----------------------------------------------
144 | ::loop_end::
145 |
146 | local indent_length = g.penvim_indentor_length
147 | local tab_set = false
148 | local space_set = false
149 |
150 | opt.smarttab = true -- / indent/dedent in leading whitespace
151 | opt.autoindent = true -- maintain indent of current line
152 |
153 | if stack_tab > stack_space then
154 | -- set tab
155 | opt.tabstop = indent_length -- spaces per tab
156 | opt.shiftwidth = indent_length -- spaces per tab (when shifting), when using the >> or << commands, shift lines by 4 spaces
157 | opt.softtabstop = indent_length -- Number of spaces that a counts for while performing editing operations, like inserting a or using .
158 | opt.expandtab = false -- Always uses spaces instead of tab characters (et).
159 | tab_set = true
160 | end
161 | if stack_space > stack_tab then
162 | -- set space
163 | local space_length
164 | if #space_list <= 1 then
165 | space_length = space_list[1]
166 | else
167 | space_length = math.min(unpack(space_list))
168 | end
169 |
170 | opt.tabstop = space_length -- Size of a hard tabstop (ts).
171 | opt.shiftwidth = space_length -- Size of an indentation (sw).
172 | opt.softtabstop = 0 -- Number of spaces a counts for. When 0, featuer is off (sts).
173 | opt.expandtab = true -- Always uses spaces instead of tab characters (et).
174 | space_set = true
175 | end
176 |
177 | if not tab_set and not space_set then
178 | -- use default
179 | local indent_type = g.penvim_indentor_type -- default auto, auto|space|tab
180 |
181 | if indent_type == "tab" then
182 | -- TAB
183 | opt.softtabstop = indent_length
184 | opt.shiftwidth = indent_length -- spaces per tab (when shifting), when using the >> or << commands, shift lines by 4 spaces
185 | opt.tabstop = indent_length -- Size of a hard tabstop (ts).
186 | elseif indent_type == "space" then
187 | -- SPACE
188 | opt.softtabstop = 0 -- Number of spaces a counts for. When 0, featuer is off (sts).
189 | opt.expandtab = true -- Always uses spaces instead of tab characters (et).
190 | opt.shiftwidth = indent_length -- spaces per tab (when shifting), when using the >> or << commands, shift lines by 4 spaces
191 | opt.tabstop = indent_length -- Size of a hard tabstop (ts).
192 | else
193 | -- TODO --
194 | -- auto
195 | return
196 | end
197 | end
198 | end
199 |
200 |
201 | return M
202 |
203 |
--------------------------------------------------------------------------------
/lua/penvim/init.lua:
--------------------------------------------------------------------------------
1 |
2 | local M={}
3 | local g = vim.g
4 | local api = vim.api
5 | local bo = vim.bo
6 |
7 |
8 | local default = {
9 | project_env = {
10 | enable = true,
11 | config_name = '.__nvim__.lua'
12 | },
13 |
14 | langs = {
15 | enable = false
16 | },
17 |
18 | rooter = {
19 | enable = true,
20 | patterns = {
21 | '.__nvim__.lua', '.git', 'node_modules', '.sln', '.svn', 'wwwroot', '.projectile',
22 | 'rebar.config', -- Rebar project file
23 | 'project.clj', --Leiningen project file
24 | 'build.boot', --Boot-clj project file
25 | 'deps.edn', --Clojure CLI project file
26 | 'SConstruct', --Scons project file
27 | 'default.nix', --Nix project file
28 | 'flake.nix', --Nix flake project file
29 | 'pom.xml', --Maven project file
30 | 'build.sbt', --SBT project file
31 | 'build.sc', --Mill project file
32 | 'gradlew', --Gradle wrapper script
33 | 'build.gradle', --Gradle project file
34 | '.ensime', --Ensime configuration file
35 | 'Gemfile', --Bundler file
36 | 'requirements.txt', --Pip file
37 | 'setup.py', --Setuptools file
38 | 'tox.ini', --Tox file
39 | 'composer.json', --Composer project file
40 | 'Cargo.toml', --Cargo project file
41 | 'mix.exs', --Elixir mix project file
42 | 'stack.yaml', --Haskell’s stack tool based project
43 | 'dune-project', --OCaml Dune project file
44 | 'info.rkt', --Racket package description file
45 | 'DESCRIPTION', --R package description file
46 | --TAGS etags/ctags are usually in the root of project', --GTAGS GNU Global tags
47 | 'configure.in', --autoconf old style
48 | 'configure.ac', --autoconf new style
49 | 'cscope.out', --cscope
50 | 'go.mod', -- go project
51 | }
52 | },
53 |
54 | -- indentor
55 | indentor = {
56 | enable = true, -- enable/disable indentor
57 | indent_length = 4, -- tab indent width or no of spaces in case of indent_type
58 | indent_type = "auto", -- if file is new or it doesn't have any indentation (auto, tab, space)
59 | accuracy = 5, -- positive integer. higher the number, the more accurate result (but affects the startup time)
60 | disable_types = {
61 | 'help','dashboard','dashpreview','NvimTree','vista','sagahover'
62 | },
63 | },
64 | }
65 |
66 |
67 | function M.setup(options)
68 |
69 | -- default options
70 | ---------------------------------------
71 | -- project_env default config
72 | g.penvim_project_enable = default.project_env.enable
73 | g.penvim_project_config = default.project_env.config_name
74 | -- langs default config
75 | g.penvim_langs_enable = default.langs.enable
76 | -- rooter default config
77 | g.penvim_rooter_enable = default.rooter.enable
78 | g.penvim_rooter_patterns = default.rooter.patterns
79 | -- indentor default config
80 | g.penvim_indentor_enable = default.indentor.enable
81 | g.penvim_indentor_length = default.indentor.indent_length
82 | g.penvim_indentor_indent = default.indentor.indent_type
83 | g.penvim_indentor_accuracy = default.indentor.accuracy
84 | local disable_types = default.indentor.disable_types
85 |
86 | --
87 | local filetype = bo.filetype
88 | local buftype = bo.buftype
89 |
90 |
91 | -- overide default options with user-defined options
92 | ---------------------------------------
93 | if options ~= nil then
94 | -- project_env
95 | if options.project_env ~= nil then
96 | if options.project_env.enable ~= nil then
97 | g.penvim_project_enable = options.project_env.enable
98 | end
99 | if options.project_env.config_name ~=nil then
100 | g.penvim_project_config = options.project_env.config_name
101 | end
102 | end
103 |
104 | -- langs
105 | if options.langs ~= nil and options.langs.enable ~= nil then
106 | g.penvim_langs_enable = options.langs.enable
107 | end
108 |
109 | -- rooter
110 | if options.rooter ~= nil then
111 | if options.rooter.enable ~= nil then
112 | g.penvim_rooter_enable = options.rooter.enable
113 | end
114 | if options.rooter.patterns ~= nil then
115 | local default_pattern = default.rooter.patterns
116 | local option_pattern = options.rooter.patterns
117 |
118 | for _, value in pairs(option_pattern) do
119 | default_pattern[#default_pattern+1] = value
120 | end
121 | g.penvim_rooter_patterns = default_pattern
122 | end
123 | end
124 |
125 | -- indentor
126 | if options.indentor ~= nil then
127 | if options.indentor.enable ~= nil then
128 | g.penvim_indentor_enable = options.indentor.enable
129 | end
130 | if options.indentor.indent_length ~=nil then
131 | g.penvim_indentor_length = options.indentor.indent_length
132 | end
133 | if options.indentor.indent_type ~=nil then
134 | g.penvim_indentor_indent = options.indentor.indent_type
135 | end
136 | if options.indentor.accuracy ~=nil then
137 | g.penvim_indentor_accuracy = options.indentor.accuracy
138 | end
139 | if options.indentor.disable_types ~=nil then
140 | local default_disable_types = default.indentor.disable_types
141 | local option_disable_types = options.indentor.disable_types
142 | for _, value in pairs(option_disable_types) do
143 | default_disable_types[#default_disable_types+1] = value
144 | end
145 | disable_types = default_disable_types
146 | end
147 | end
148 | end
149 |
150 | local group = api.nvim_create_augroup("PenvimAutoGroup", {clear=true})
151 |
152 | -- TODO:
153 | -- language
154 | ---------------------------------------
155 | if g.penvim_langs_enable then
156 | api.nvim_create_autocmd(
157 | "BufEnter",
158 | {
159 | pattern = "*",
160 | group = group,
161 | command = "lua require('penvim.langs').load_langs()"
162 | }
163 | )
164 | end
165 |
166 | -- project environment
167 | ---------------------------------------
168 | if g.penvim_project_enable then
169 | api.nvim_create_autocmd(
170 | "BufEnter",
171 | {
172 | pattern = "*",
173 | group = group,
174 | command = "lua require('penvim.project_env').load_project_config()"
175 | }
176 | )
177 | end
178 |
179 | -- rooter
180 | ---------------------------------------
181 | if g.penvim_rooter_enable then
182 | api.nvim_create_autocmd(
183 | "BufEnter",
184 | {
185 | pattern = "*",
186 | group = group,
187 | command = "lua require('penvim.rooter').load_rooter()"
188 | }
189 | )
190 | end
191 |
192 | -- TODO:
193 | -- indentor
194 | ---------------------------------------
195 | if g.penvim_indentor_enable then
196 |
197 | -- don't load indentor if filetype is passed in options
198 | for _, ft in pairs(disable_types) do
199 | if ft==filetype or ft==buftype then
200 | return
201 | end
202 | end
203 |
204 | api.nvim_create_autocmd(
205 | "BufEnter",
206 | {
207 | pattern = "*",
208 | group = group,
209 | command = "lua require('penvim.indentor').load_indentor()"
210 | }
211 | )
212 | end
213 |
214 | end
215 |
216 |
217 | return M
218 |
219 |
--------------------------------------------------------------------------------