aboutsummaryrefslogtreecommitdiff
path: root/plugins/indent_convert.lua
diff options
context:
space:
mode:
authorGuldoman <giulio.lettieri@gmail.com>2021-11-19 19:15:50 +0100
committerGuldoman <giulio.lettieri@gmail.com>2021-11-19 19:15:50 +0100
commit333388602d6be6a967d07f0324bc8cefb8351a17 (patch)
tree1096b3f9c914d004d6be2f3cc3219f4a07e73498 /plugins/indent_convert.lua
parentbc0a289a79294445de9b0001bdaada93d801dadd (diff)
downloadlite-xl-plugins-333388602d6be6a967d07f0324bc8cefb8351a17.tar.gz
lite-xl-plugins-333388602d6be6a967d07f0324bc8cefb8351a17.zip
Add `indent_convert`
Diffstat (limited to 'plugins/indent_convert.lua')
-rw-r--r--plugins/indent_convert.lua100
1 files changed, 100 insertions, 0 deletions
diff --git a/plugins/indent_convert.lua b/plugins/indent_convert.lua
new file mode 100644
index 0000000..103f271
--- /dev/null
+++ b/plugins/indent_convert.lua
@@ -0,0 +1,100 @@
+-- mod-version:2 -- lite-xl 2.0
+local core = require "core"
+local config = require "core.config"
+local command = require "core.command"
+
+config.plugins.indent_convert = {
+ update_indent_type = true -- set to false to avoid updating the document indent type
+}
+
+-- To replace N spaces with tabs, we match the last N spaces before the start of
+-- the actual code and replace them with a tab.
+-- We repeat this until we can't find any more spaces before the code.
+-- The problem we encounter with this method is that if we have less than N
+-- remaining spaces, those will end up at the start of the line.
+-- Eg:
+-- int main() {
+-- __printf("Hello world\n");
+-- ___return 0;
+-- }
+--
+-- Becomes
+-- int main() {
+-- #printf("Hello world\n");
+-- _#return 0;
+-- }
+--
+-- Instead of
+-- int main() {
+-- #printf("Hello world\n");
+-- #_return 0;
+-- }
+-- With regex we could do something like
+-- `regex.gsub("(^(?: {2})*)(?: {2})", "\\1\t")`
+-- but the implementation of `regex.gsub` is very slow.
+--
+-- The workaround is to find the longest possible repetition of N*X spaces and
+-- use that information to replace the longest repetition of spaces starting
+-- from the beginning of the line, then the second longest...
+local function spaces_replacer(text)
+ local spaces = string.rep(" ", config.indent_size)
+ local total = 0
+ local n
+ local reps = 0
+ -- find the longest repetition of indent_size*spaces
+ repeat
+ reps = reps + 1
+ local s, _ = string.find(text, "%f[^\0\n]"..string.rep(spaces, reps))
+ until not s
+ reps = reps - 1
+ while reps > 0 do
+ text, n = string.gsub(text,
+ "(%f[^\0\n])("..string.rep(spaces, reps)..")",
+ "%1"..string.rep("\t", reps))
+ total = total + n
+ reps = reps - 1
+ end
+ return text, total
+end
+
+local function tabs_replacer(text)
+ local spaces = string.rep(" ", config.indent_size)
+ local total = 0
+ local n
+ -- replace the last tab before the text until there aren't anymore
+ repeat
+ text, n = string.gsub(text, "(%f[^\0\n]\t*)(\t)", "%1"..spaces)
+ total = total + n
+ until n == 0
+ return text, total
+end
+
+local function tabs_to_spaces()
+ local doc = core.active_view.doc
+ doc:replace(tabs_replacer)
+ if config.plugins.indent_convert.update_indent_type then
+ doc.indent_info = {
+ type = "soft",
+ size = config.indent_size,
+ confirmed = true
+ }
+ end
+end
+
+local function spaces_to_tabs()
+ local doc = core.active_view.doc
+ doc:replace(spaces_replacer)
+ if config.plugins.indent_convert.update_indent_type then
+ doc.indent_info = {
+ type = "hard",
+ size = config.indent_size,
+ confirmed = true
+ }
+ end
+end
+
+command.add("core.docview", {
+ ["indent-convert:tabs-to-spaces"] = tabs_to_spaces,
+ ["indent-convert:spaces-to-tabs"] = spaces_to_tabs
+ }
+)