aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--plugins/wordcount.lua90
2 files changed, 91 insertions, 0 deletions
diff --git a/README.md b/README.md
index 0ae6c1f..10b6103 100644
--- a/README.md
+++ b/README.md
@@ -174,3 +174,4 @@ to something other than a raw file it should be marked with an asterisk.*
| [`vibe`](https://github.com/eugenpt/lite-xl-vibe)\* | VI(vim?) bindings with a hint of DOOM Emacs, for lite-xl |
| [`visu`](https://github.com/TorchedSammy/Visu)\* | Audio visualizer for Lite XL |
| [`widget`](https://github.com/lite-xl/lite-xl-widgets)\* | Plugin library that provides a set of re-usable components to more easily write UI elements for your plugins |
+| [`wordcount`](plugins/wordcount.lua?raw=1) | Adds in a word count to the statusview. |
diff --git a/plugins/wordcount.lua b/plugins/wordcount.lua
new file mode 100644
index 0000000..224ad5e
--- /dev/null
+++ b/plugins/wordcount.lua
@@ -0,0 +1,90 @@
+-- mod-version:3
+local core = require "core"
+local style = require "core.style"
+local StatusView = require "core.statusview"
+local CommandView = require "core.commandview"
+local DocView = require "core.docview"
+local Doc = require "core.doc"
+local keymap = require "core.keymap"
+
+
+local words = setmetatable({}, { __mode = "k" })
+
+
+local function compute_line_words(line)
+ local s, total_words = 1, 0
+ while true do
+ local ns, e = line:find("%s+", s)
+ if ns == 1 and e == #line then break end
+ if not e then total_words = math.max(total_words, 1) break end
+ total_words = total_words + 1
+ s = e + 1
+ end
+ return total_words
+end
+
+
+local function compute_words(doc, start_line, end_line)
+ local total_words = 0
+ for i = start_line or 1, end_line or #doc.lines do
+ total_words = total_words + compute_line_words(doc.lines[i])
+ end
+ return total_words
+end
+
+
+local old_raw_insert = Doc.raw_insert
+function Doc:raw_insert(line, col, text, undo_stack, time)
+ if words[self] then
+ local old_count = compute_words(self, line, line)
+ old_raw_insert(self, line, col, text, undo_stack, time)
+ local total_lines, s = 0, 0
+ while true do
+ s = text:find("\n", s + 1, true)
+ if not s then break end
+ total_lines = total_lines + 1
+ end
+ words[self] = words[self] + compute_words(self, line, line + total_lines) - old_count
+ else
+ old_raw_insert(self, line, col, text, undo_stack, time)
+ end
+end
+
+
+local old_raw_remove = Doc.raw_remove
+function Doc:raw_remove(line1, col1, line2, col2, undo_stack, time)
+ if words[self] then
+ local old_count = compute_words(self, line1, line2)
+ old_raw_remove(self, line1, col1, line2, col2, undo_stack, time)
+ words[self] = words[self] + compute_words(self, line1, line1) - old_count
+ else
+ old_raw_remove(self, line1, col1, line2, col2, undo_stack, time)
+ end
+end
+
+
+local old_doc_new = Doc.new
+function Doc:new(...)
+ old_doc_new(self, ...)
+ words[self] = compute_words(self)
+end
+
+local cached_word_length, cached_word_count
+
+core.status_view:add_item(
+ function() return core.active_view:is(DocView) and not core.active_view:is(CommandView) and words[core.active_view.doc] end,
+ "status:word-count",
+ StatusView.Item.RIGHT,
+ function()
+ local selection_text = core.active_view.doc:get_selection_text()
+ if #selection_text ~= cached_word_length then
+ cached_word_count = compute_line_words(selection_text)
+ cached_word_length = #selection_text
+ end
+ if #selection_text > 0 then
+ return { style.text, cached_word_count .. " words" }
+ else
+ return { style.text, words[core.active_view.doc] .. " words" }
+ end
+ end
+)