From 43d6e5486f01222ee71f937db931696083d0b065 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Thu, 17 Oct 2024 23:08:32 +0100
Subject: [PATCH 01/27] added 3 new colour schemes
---
config/catppuccin-mocha.lua | 83 +++++++++++
config/ox-transparent.lua | 268 ++++++++++++++++++++++++++++++++++++
config/tropical.lua | 85 ++++++++++++
3 files changed, 436 insertions(+)
create mode 100644 config/catppuccin-mocha.lua
create mode 100644 config/ox-transparent.lua
create mode 100644 config/tropical.lua
diff --git a/config/catppuccin-mocha.lua b/config/catppuccin-mocha.lua
new file mode 100644
index 00000000..87afdeaa
--- /dev/null
+++ b/config/catppuccin-mocha.lua
@@ -0,0 +1,83 @@
+-- Define user-defined commands
+commands = {
+ ["reload"] = function(arguments)
+ editor:reload_config()
+ editor:display_info("Configuration file and plugins reloaded")
+ end,
+}
+
+-- Pallette --
+black = '#1e1e2e'
+darkgrey = '#24273a'
+lightgrey = '#303446'
+verylightgrey = '#7f849c'
+white = '#cdd6f4'
+brown = '#f2cdcd'
+red = '#f38ba8'
+orange = '#fab387'
+yellow = '#f9e2af'
+green = '#a6e3a1'
+lightblue = '#89dceb'
+darkblue = '#89b4fa'
+purple = '#cba6f7'
+pink = '#f5c2e7'
+
+-- Configure Colours --
+colors.editor_bg = black
+colors.editor_fg = white
+colors.line_number_fg = lightgrey
+colors.line_number_bg = black
+
+colors.status_bg = darkgrey
+colors.status_fg = purple
+
+colors.highlight = purple
+
+colors.tab_inactive_bg = darkgrey
+colors.tab_inactive_fg = white
+colors.tab_active_bg = lightgrey
+colors.tab_active_fg = purple
+
+colors.info_bg = black
+colors.info_fg = lightblue
+colors.warning_bg = black
+colors.warning_fg = yellow
+colors.error_bg = black
+colors.error_fg = red
+
+colors.selection_bg = darkgrey
+colors.selection_fg = lightblue
+
+-- Configure Syntax Highlighting Colours --
+syntax:set("string", green) -- Strings, bright green
+syntax:set("comment", verylightgrey) -- Comments, light purple/gray
+syntax:set("digit", red) -- Digits, cyan
+syntax:set("keyword", purple) -- Keywords, vibrant pink
+syntax:set("attribute", lightblue) -- Attributes, cyan
+syntax:set("character", darkblue) -- Characters, cyan
+syntax:set("type", yellow) -- Types, light purple
+syntax:set("function", darkblue) -- Function names, light purple
+syntax:set("header", lightblue) -- Headers, cyan
+syntax:set("macro", red) -- Macros, red
+syntax:set("namespace", darkblue) -- Namespaces, light purple
+syntax:set("struct", pink) -- Structs, classes, and enums, light purple
+syntax:set("operator", verylightgrey) -- Operators, light purple/gray
+syntax:set("boolean", green) -- Booleans, bright green
+syntax:set("table", purple) -- Tables, light purple
+syntax:set("reference", pink) -- References, vibrant pink
+syntax:set("tag", darkblue) -- Tags (e.g. HTML tags), cyan
+syntax:set("heading", purple) -- Headings, light purple
+syntax:set("link", pink) -- Links, vibrant pink
+syntax:set("key", pink) -- Keys, vibrant pink
+syntax:set("quote", verylightgrey) -- Quotes, light purple/gray
+syntax:set("bold", red) -- Bold text, cyan
+syntax:set("italic", orange) -- Italic text, cyan
+syntax:set("block", lightblue) -- Code blocks, cyan
+syntax:set("image", lightblue) -- Images in markup languages, cyan
+syntax:set("list", green) -- Lists, bright green
+syntax:set("insertion", green) -- Insertions (e.g. diff highlight), bright green
+syntax:set("deletion", red) -- Deletions (e.g. diff highlight), red
+
+-- Import plugins (must be at the bottom of this file)
+load_plugin("pairs.lua")
+load_plugin("autoindent.lua")
diff --git a/config/ox-transparent.lua b/config/ox-transparent.lua
new file mode 100644
index 00000000..21991a50
--- /dev/null
+++ b/config/ox-transparent.lua
@@ -0,0 +1,268 @@
+-- Configure Events --
+event_mapping = {
+ -- Cursor movement
+ ["up"] = function()
+ editor:move_up()
+ end,
+ ["down"] = function()
+ editor:move_down()
+ end,
+ ["left"] = function()
+ editor:move_left()
+ end,
+ ["right"] = function()
+ editor:move_right()
+ end,
+ ["shift_up"] = function()
+ editor:select_up()
+ end,
+ ["shift_down"] = function()
+ editor:select_down()
+ end,
+ ["shift_left"] = function()
+ editor:select_left()
+ end,
+ ["shift_right"] = function()
+ editor:select_right()
+ end,
+ ["ctrl_up"] = function()
+ editor:move_top()
+ end,
+ ["ctrl_down"] = function()
+ editor:move_bottom()
+ end,
+ ["ctrl_left"] = function()
+ editor:move_previous_word()
+ end,
+ ["ctrl_right"] = function()
+ editor:move_next_word()
+ end,
+ ["home"] = function()
+ editor:move_home()
+ end,
+ ["end"] = function()
+ editor:move_end()
+ end,
+ ["pageup"] = function()
+ editor:move_page_up()
+ end,
+ ["pagedown"] = function()
+ editor:move_page_down()
+ end,
+ ["ctrl_g"] = function()
+ local line = editor:prompt("Go to line")
+ editor:move_to(0, tonumber(line))
+ end,
+ -- Searching & Replacing
+ ["ctrl_f"] = function()
+ editor:search()
+ end,
+ ["ctrl_r"] = function()
+ editor:replace()
+ end,
+ -- Document Management
+ ["ctrl_n"] = function()
+ editor:new()
+ end,
+ ["ctrl_o"] = function()
+ editor:open()
+ end,
+ ["ctrl_s"] = function()
+ editor:save()
+ end,
+ ["alt_s"] = function()
+ editor:save_as()
+ end,
+ ["alt_a"] = function()
+ editor:save_all()
+ end,
+ ["ctrl_q"] = function()
+ editor:quit()
+ end,
+ ["alt_left"] = function()
+ editor:previous_tab()
+ end,
+ ["alt_right"] = function()
+ editor:next_tab()
+ end,
+ -- Clipboard Interaction
+ ["ctrl_a"] = function()
+ editor:select_all()
+ end,
+ ["ctrl_x"] = function()
+ editor:cut()
+ end,
+ ["ctrl_c"] = function()
+ editor:copy()
+ end,
+ ["ctrl_v"] = function()
+ editor:display_info("Use ctrl+shift+v for paste or set your terminal emulator to do paste on ctrl+v")
+ end,
+ -- Undo & Redo
+ ["ctrl_z"] = function()
+ editor:undo()
+ end,
+ ["ctrl_y"] = function()
+ editor:redo()
+ end,
+ -- Miscellaneous
+ ["ctrl_h"] = function()
+ help_message.enabled = not help_message.enabled
+ end,
+ ["ctrl_d"] = function()
+ editor:remove_line()
+ end,
+ ["ctrl_k"] = function()
+ editor:open_command_line()
+ end,
+ ["alt_up"] = function()
+ -- current line information
+ line = editor:get_line()
+ y = editor.cursor.y
+ -- insert a new line
+ editor:insert_line_at(line, y - 1)
+ -- delete old copy and reposition cursor
+ editor:remove_line_at(y + 1)
+ editor:move_up()
+ -- correct indentation level
+ autoindent:fix_indent()
+ end,
+ ["alt_down"] = function()
+ -- current line information
+ line = editor:get_line()
+ y = editor.cursor.y
+ -- insert a new line
+ editor:insert_line_at(line, y + 2)
+ -- delete old copy and reposition cursor
+ editor:remove_line_at(y)
+ editor:move_down()
+ -- correct indentation level
+ autoindent:fix_indent()
+ end,
+ ["ctrl_w"] = function()
+ y = editor.cursor.y
+ x = editor.cursor.x
+ if editor:get_character() == " " then
+ start = 0
+ else
+ start = 1
+ end
+ editor:move_previous_word()
+ new_x = editor.cursor.x
+ diff = x - new_x
+ if editor.cursor.y == y then
+ -- Cursor on the same line
+ for i = start, diff do
+ editor:remove_at(new_x, y)
+ end
+ else
+ -- Cursor has passed up onto the previous line
+ end
+ end,
+}
+
+-- Define user-defined commands
+commands = {
+ ["readonly"] = function(arguments)
+ arg = arguments[1]
+ if arg == "true" then
+ editor:set_read_only(true)
+ elseif arg == "false" then
+ editor:set_read_only(false)
+ end
+ end,
+ ["filetype"] = function(arguments)
+ local file_type_name = table.concat(arguments, " ")
+ editor:set_file_type(file_type_name)
+ end,
+ ["reload"] = function(arguments)
+ editor:reload_config()
+ editor:reload_plugins()
+ editor:display_info("Configuration file and plugins reloaded")
+ end,
+}
+
+-- Configure Documents --
+document.tab_width = 4
+document.indentation = "spaces"
+document.undo_period = 10
+document.wrap_cursor = true
+
+-- Configure Colours --
+colors.editor_bg = 'transparent'
+colors.editor_fg = {255, 255, 255}
+colors.line_number_fg = {65, 65, 98}
+colors.line_number_bg = 'transparent'
+
+colors.status_bg = {59, 59, 84}
+colors.status_fg = {35, 240, 144}
+
+colors.highlight = {35, 240, 144}
+
+colors.tab_inactive_fg = {255, 255, 255}
+colors.tab_inactive_bg = {41, 41, 61}
+colors.tab_active_fg = {35, 240, 144}
+colors.tab_active_bg = {59, 59, 84}
+
+colors.info_fg = {99, 162, 255}
+colors.info_bg = 'transparent'
+colors.warning_fg = {255, 182, 99}
+colors.warning_bg = 'transparent'
+colors.error_fg = {255, 100, 100}
+colors.error_bg = 'transparent'
+
+colors.selection_fg = {255, 255, 255}
+colors.selection_bg = {59, 59, 130}
+
+-- Configure Line Numbers --
+line_numbers.enabled = true
+line_numbers.padding_left = 1
+line_numbers.padding_right = 1
+
+-- Configure Mouse Behaviour --
+terminal.mouse_enabled = true
+
+-- Configure Tab Line --
+tab_line.enabled = true
+tab_line.format = " {file_name}{modified} "
+
+-- Configure Status Line --
+status_line:add_part(" {file_name}{modified} │ {file_type} │") -- The left side of the status line
+status_line:add_part("│ {cursor_y} / {line_count} {cursor_x} ") -- The right side of the status line
+
+status_line.alignment = "between" -- This will put a space between the left and right sides
+
+-- Configure Greeting and Help Messages --
+greeting_message.enabled = true
+help_message.enabled = false
+
+-- Configure Syntax Highlighting Colours --
+syntax:set("string", {39, 222, 145}) -- Strings in various programming languages
+syntax:set("comment", {113, 113, 169}) -- Comments in various programming languages
+syntax:set("digit", {40, 198, 232}) -- Digits in various programming languages
+syntax:set("keyword", {134, 76, 232}) -- Keywords in various programming languages
+syntax:set("attribute", {40, 198, 232}) -- Attributes in various programming languages
+syntax:set("character", {40, 198, 232}) -- Characters in various programming languages
+syntax:set("type", {47, 141, 252}) -- Types in various programming languages
+syntax:set("function", {47, 141, 252}) -- Function names in various programming languages
+syntax:set("header", {40, 198, 232}) -- Headers in various programming language
+syntax:set("macro", {223, 52, 249}) -- Macro names in various programming languages
+syntax:set("namespace", {47, 141, 252}) -- Namespaces in various programming languages
+syntax:set("struct", {47, 141, 252}) -- The names of structs, classes, enums in various programming languages
+syntax:set("operator", {113, 113, 169}) -- Operators in various programming languages e.g. +, -, * etc
+syntax:set("boolean", {86, 217, 178}) -- Booleans in various programming langauges e.g. true / false
+syntax:set("table", {47, 141, 252}) -- Tables in various programming languages
+syntax:set("reference", {134, 76, 232}) -- References in various programming languages
+syntax:set("tag", {40, 198, 232}) -- Tags in various markup langauges e.g. HTML
tags
+syntax:set("heading", {47, 141, 252}) -- Headings in various markup languages e.g. # in markdown
+syntax:set("link", {223, 52, 249}) -- Links in various markup languages e.g. URLs
+syntax:set("key", {223, 52, 249}) -- Keys in various markup languages
+syntax:set("quote", {113, 113, 169}) -- Quotes in various markup languages e.g. > in markdown
+syntax:set("bold", {40, 198, 232}) -- Quotes in various markup languages e.g. * in markdown
+syntax:set("italic", {40, 198, 232}) -- Quotes in various markup languages e.g. _ in markdown
+syntax:set("block", {40, 198, 232}) -- Quotes in various markup languages e.g. _ in markdown
+syntax:set("list", {86, 217, 178}) -- Quotes in various markup languages e.g. _ in markdown
+
+-- Import plugins (must be at the bottom of this file)
+load_plugin("pairs.lua")
+load_plugin("autoindent.lua")
diff --git a/config/tropical.lua b/config/tropical.lua
new file mode 100644
index 00000000..3e4eabae
--- /dev/null
+++ b/config/tropical.lua
@@ -0,0 +1,85 @@
+-- Define user-defined commands
+commands = {
+ ["reload"] = function(arguments)
+ editor:reload_config()
+ editor:display_info("Configuration file and plugins reloaded")
+ end,
+}
+
+-- Pallette --
+black = '#232336'
+darkgrey = '#353552'
+lightgrey = '#484863'
+verylightgrey = '#A1A7C7'
+white = '#cdd6f4'
+brown = '#dd7878'
+red = '#ed8796'
+orange = '#f5a97f'
+yellow = '#eed49f'
+green = '#a6da95'
+lightblue = '#7dc4e4'
+darkblue = '#8aadf4'
+purple = '#c6a0f6'
+pink = '#f5bde6'
+
+-- PRIORITISE - ORANGE, RED, YELLOW, DARKBLUE, BROWN, GREEN, PINK
+
+-- Configure Colours --
+colors.editor_bg = black
+colors.editor_fg = white
+colors.line_number_fg = lightgrey
+colors.line_number_bg = black
+
+colors.status_bg = darkgrey
+colors.status_fg = orange
+
+colors.highlight = orange
+
+colors.tab_inactive_bg = darkgrey
+colors.tab_inactive_fg = white
+colors.tab_active_bg = lightgrey
+colors.tab_active_fg = orange
+
+colors.info_bg = black
+colors.info_fg = lightblue
+colors.warning_bg = black
+colors.warning_fg = yellow
+colors.error_bg = black
+colors.error_fg = red
+
+colors.selection_bg = darkgrey
+colors.selection_fg = lightblue
+
+-- Configure Syntax Highlighting Colours --
+syntax:set("string", lightblue) -- Strings, bright green
+syntax:set("comment", verylightgrey) -- Comments, light purple/gray
+syntax:set("digit", lightblue) -- Digits, cyan
+syntax:set("keyword", orange) -- Keywords, vibrant pink
+syntax:set("attribute", darkblue) -- Attributes, cyan
+syntax:set("character", orange) -- Characters, cyan
+syntax:set("type", pink) -- Types, light purple
+syntax:set("function", red) -- Function names, light purple
+syntax:set("header", darkblue) -- Headers, cyan
+syntax:set("macro", darkblue) -- Macros, red
+syntax:set("namespace", pink) -- Namespaces, light purple
+syntax:set("struct", yellow) -- Structs, classes, and enums, light purple
+syntax:set("operator", darkblue) -- Operators, light purple/gray
+syntax:set("boolean", pink) -- Booleans, bright green
+syntax:set("table", yellow) -- Tables, light purple
+syntax:set("reference", yellow) -- References, vibrant pink
+syntax:set("tag", orange) -- Tags (e.g. HTML tags), cyan
+syntax:set("heading", red) -- Headings, light purple
+syntax:set("link", darkblue) -- Links, vibrant pink
+syntax:set("key", yellow) -- Keys, vibrant pink
+syntax:set("quote", verylightgrey) -- Quotes, light purple/gray
+syntax:set("bold", red) -- Bold text, cyan
+syntax:set("italic", orange) -- Italic text, cyan
+syntax:set("block", red) -- Code blocks, cyan
+syntax:set("image", red) -- Images in markup languages, cyan
+syntax:set("list", red) -- Lists, bright green
+syntax:set("insertion", green) -- Insertions (e.g. diff highlight), bright green
+syntax:set("deletion", red) -- Deletions (e.g. diff highlight), red
+
+-- Import plugins (must be at the bottom of this file)
+load_plugin("pairs.lua")
+load_plugin("autoindent.lua")
From 3460f3ecfcb9561a59f55ca46298de7aad08b539 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Thu, 17 Oct 2024 23:41:49 +0100
Subject: [PATCH 02/27] version bump
---
Cargo.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Cargo.toml b/Cargo.toml
index 03ac7a40..b118568f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,7 +7,7 @@ exclude = ["cactus"]
[package]
name = "ox"
-version = "0.6.7"
+version = "0.6.8"
edition = "2021"
authors = ["Curlpipe <11898833+curlpipe@users.noreply.github.com>"]
description = "A Rust powered text editor."
From 556064850cb9f1d5d6c3197e3d5d831fc4676c62 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Fri, 18 Oct 2024 23:10:28 +0100
Subject: [PATCH 03/27] Added configuration assistant
---
Cargo.lock | 2 +-
config/.oxrc | 11 +-
config/ox-transparent.lua | 268 -------
src/cli.rs | 6 +-
src/config/assistant.rs | 689 ++++++++++++++++++
src/config/colors.rs | 38 +-
src/config/highlighting.rs | 40 +-
src/config/interface.rs | 23 +-
src/config/mod.rs | 33 +-
src/editor/mod.rs | 2 +-
src/main.rs | 13 +-
.../themes/galaxy.lua | 33 +-
src/themes/transparent.lua | 8 +
{config => src/themes}/tropical.lua | 35 +-
14 files changed, 833 insertions(+), 368 deletions(-)
delete mode 100644 config/ox-transparent.lua
create mode 100644 src/config/assistant.rs
rename config/catppuccin-mocha.lua => src/themes/galaxy.lua (73%)
create mode 100644 src/themes/transparent.lua
rename {config => src/themes}/tropical.lua (73%)
diff --git a/Cargo.lock b/Cargo.lock
index 0232a3b2..c4e11b78 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -306,7 +306,7 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "ox"
-version = "0.6.7"
+version = "0.6.8"
dependencies = [
"alinio",
"base64",
diff --git a/config/.oxrc b/config/.oxrc
index 1d25c0b8..015d7e11 100644
--- a/config/.oxrc
+++ b/config/.oxrc
@@ -232,17 +232,18 @@ line_numbers.padding_right = 1
-- Configure Mouse Behaviour --
terminal.mouse_enabled = true
-terminal.scroll_amount = 1
+terminal.scroll_amount = 2
-- Configure Tab Line --
tab_line.enabled = true
tab_line.format = " {file_name}{modified} "
-- Configure Status Line --
-status_line:add_part(" {file_name}{modified} │ {file_type} │") -- The left side of the status line
-status_line:add_part("│ {cursor_y} / {line_count} {cursor_x} ") -- The right side of the status line
-
-status_line.alignment = "between" -- This will put a space between the left and right sides
+status_line.parts = {
+ " {file_name}{modified} │ {file_type} │", -- The left side of the status line
+ "│ {cursor_y} / {line_count} {cursor_x} ", -- The right side of the status line
+}
+status_line.alignment = "between" -- This will put a space between the parts (left and right sides)
-- Configure Greeting Message --
greeting_message.enabled = true
diff --git a/config/ox-transparent.lua b/config/ox-transparent.lua
deleted file mode 100644
index 21991a50..00000000
--- a/config/ox-transparent.lua
+++ /dev/null
@@ -1,268 +0,0 @@
--- Configure Events --
-event_mapping = {
- -- Cursor movement
- ["up"] = function()
- editor:move_up()
- end,
- ["down"] = function()
- editor:move_down()
- end,
- ["left"] = function()
- editor:move_left()
- end,
- ["right"] = function()
- editor:move_right()
- end,
- ["shift_up"] = function()
- editor:select_up()
- end,
- ["shift_down"] = function()
- editor:select_down()
- end,
- ["shift_left"] = function()
- editor:select_left()
- end,
- ["shift_right"] = function()
- editor:select_right()
- end,
- ["ctrl_up"] = function()
- editor:move_top()
- end,
- ["ctrl_down"] = function()
- editor:move_bottom()
- end,
- ["ctrl_left"] = function()
- editor:move_previous_word()
- end,
- ["ctrl_right"] = function()
- editor:move_next_word()
- end,
- ["home"] = function()
- editor:move_home()
- end,
- ["end"] = function()
- editor:move_end()
- end,
- ["pageup"] = function()
- editor:move_page_up()
- end,
- ["pagedown"] = function()
- editor:move_page_down()
- end,
- ["ctrl_g"] = function()
- local line = editor:prompt("Go to line")
- editor:move_to(0, tonumber(line))
- end,
- -- Searching & Replacing
- ["ctrl_f"] = function()
- editor:search()
- end,
- ["ctrl_r"] = function()
- editor:replace()
- end,
- -- Document Management
- ["ctrl_n"] = function()
- editor:new()
- end,
- ["ctrl_o"] = function()
- editor:open()
- end,
- ["ctrl_s"] = function()
- editor:save()
- end,
- ["alt_s"] = function()
- editor:save_as()
- end,
- ["alt_a"] = function()
- editor:save_all()
- end,
- ["ctrl_q"] = function()
- editor:quit()
- end,
- ["alt_left"] = function()
- editor:previous_tab()
- end,
- ["alt_right"] = function()
- editor:next_tab()
- end,
- -- Clipboard Interaction
- ["ctrl_a"] = function()
- editor:select_all()
- end,
- ["ctrl_x"] = function()
- editor:cut()
- end,
- ["ctrl_c"] = function()
- editor:copy()
- end,
- ["ctrl_v"] = function()
- editor:display_info("Use ctrl+shift+v for paste or set your terminal emulator to do paste on ctrl+v")
- end,
- -- Undo & Redo
- ["ctrl_z"] = function()
- editor:undo()
- end,
- ["ctrl_y"] = function()
- editor:redo()
- end,
- -- Miscellaneous
- ["ctrl_h"] = function()
- help_message.enabled = not help_message.enabled
- end,
- ["ctrl_d"] = function()
- editor:remove_line()
- end,
- ["ctrl_k"] = function()
- editor:open_command_line()
- end,
- ["alt_up"] = function()
- -- current line information
- line = editor:get_line()
- y = editor.cursor.y
- -- insert a new line
- editor:insert_line_at(line, y - 1)
- -- delete old copy and reposition cursor
- editor:remove_line_at(y + 1)
- editor:move_up()
- -- correct indentation level
- autoindent:fix_indent()
- end,
- ["alt_down"] = function()
- -- current line information
- line = editor:get_line()
- y = editor.cursor.y
- -- insert a new line
- editor:insert_line_at(line, y + 2)
- -- delete old copy and reposition cursor
- editor:remove_line_at(y)
- editor:move_down()
- -- correct indentation level
- autoindent:fix_indent()
- end,
- ["ctrl_w"] = function()
- y = editor.cursor.y
- x = editor.cursor.x
- if editor:get_character() == " " then
- start = 0
- else
- start = 1
- end
- editor:move_previous_word()
- new_x = editor.cursor.x
- diff = x - new_x
- if editor.cursor.y == y then
- -- Cursor on the same line
- for i = start, diff do
- editor:remove_at(new_x, y)
- end
- else
- -- Cursor has passed up onto the previous line
- end
- end,
-}
-
--- Define user-defined commands
-commands = {
- ["readonly"] = function(arguments)
- arg = arguments[1]
- if arg == "true" then
- editor:set_read_only(true)
- elseif arg == "false" then
- editor:set_read_only(false)
- end
- end,
- ["filetype"] = function(arguments)
- local file_type_name = table.concat(arguments, " ")
- editor:set_file_type(file_type_name)
- end,
- ["reload"] = function(arguments)
- editor:reload_config()
- editor:reload_plugins()
- editor:display_info("Configuration file and plugins reloaded")
- end,
-}
-
--- Configure Documents --
-document.tab_width = 4
-document.indentation = "spaces"
-document.undo_period = 10
-document.wrap_cursor = true
-
--- Configure Colours --
-colors.editor_bg = 'transparent'
-colors.editor_fg = {255, 255, 255}
-colors.line_number_fg = {65, 65, 98}
-colors.line_number_bg = 'transparent'
-
-colors.status_bg = {59, 59, 84}
-colors.status_fg = {35, 240, 144}
-
-colors.highlight = {35, 240, 144}
-
-colors.tab_inactive_fg = {255, 255, 255}
-colors.tab_inactive_bg = {41, 41, 61}
-colors.tab_active_fg = {35, 240, 144}
-colors.tab_active_bg = {59, 59, 84}
-
-colors.info_fg = {99, 162, 255}
-colors.info_bg = 'transparent'
-colors.warning_fg = {255, 182, 99}
-colors.warning_bg = 'transparent'
-colors.error_fg = {255, 100, 100}
-colors.error_bg = 'transparent'
-
-colors.selection_fg = {255, 255, 255}
-colors.selection_bg = {59, 59, 130}
-
--- Configure Line Numbers --
-line_numbers.enabled = true
-line_numbers.padding_left = 1
-line_numbers.padding_right = 1
-
--- Configure Mouse Behaviour --
-terminal.mouse_enabled = true
-
--- Configure Tab Line --
-tab_line.enabled = true
-tab_line.format = " {file_name}{modified} "
-
--- Configure Status Line --
-status_line:add_part(" {file_name}{modified} │ {file_type} │") -- The left side of the status line
-status_line:add_part("│ {cursor_y} / {line_count} {cursor_x} ") -- The right side of the status line
-
-status_line.alignment = "between" -- This will put a space between the left and right sides
-
--- Configure Greeting and Help Messages --
-greeting_message.enabled = true
-help_message.enabled = false
-
--- Configure Syntax Highlighting Colours --
-syntax:set("string", {39, 222, 145}) -- Strings in various programming languages
-syntax:set("comment", {113, 113, 169}) -- Comments in various programming languages
-syntax:set("digit", {40, 198, 232}) -- Digits in various programming languages
-syntax:set("keyword", {134, 76, 232}) -- Keywords in various programming languages
-syntax:set("attribute", {40, 198, 232}) -- Attributes in various programming languages
-syntax:set("character", {40, 198, 232}) -- Characters in various programming languages
-syntax:set("type", {47, 141, 252}) -- Types in various programming languages
-syntax:set("function", {47, 141, 252}) -- Function names in various programming languages
-syntax:set("header", {40, 198, 232}) -- Headers in various programming language
-syntax:set("macro", {223, 52, 249}) -- Macro names in various programming languages
-syntax:set("namespace", {47, 141, 252}) -- Namespaces in various programming languages
-syntax:set("struct", {47, 141, 252}) -- The names of structs, classes, enums in various programming languages
-syntax:set("operator", {113, 113, 169}) -- Operators in various programming languages e.g. +, -, * etc
-syntax:set("boolean", {86, 217, 178}) -- Booleans in various programming langauges e.g. true / false
-syntax:set("table", {47, 141, 252}) -- Tables in various programming languages
-syntax:set("reference", {134, 76, 232}) -- References in various programming languages
-syntax:set("tag", {40, 198, 232}) -- Tags in various markup langauges e.g. HTML
tags
-syntax:set("heading", {47, 141, 252}) -- Headings in various markup languages e.g. # in markdown
-syntax:set("link", {223, 52, 249}) -- Links in various markup languages e.g. URLs
-syntax:set("key", {223, 52, 249}) -- Keys in various markup languages
-syntax:set("quote", {113, 113, 169}) -- Quotes in various markup languages e.g. > in markdown
-syntax:set("bold", {40, 198, 232}) -- Quotes in various markup languages e.g. * in markdown
-syntax:set("italic", {40, 198, 232}) -- Quotes in various markup languages e.g. _ in markdown
-syntax:set("block", {40, 198, 232}) -- Quotes in various markup languages e.g. _ in markdown
-syntax:set("list", {86, 217, 178}) -- Quotes in various markup languages e.g. _ in markdown
-
--- Import plugins (must be at the bottom of this file)
-load_plugin("pairs.lua")
-load_plugin("autoindent.lua")
diff --git a/src/cli.rs b/src/cli.rs
index a7403f39..2d589d5d 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -19,6 +19,7 @@ OPTIONS:
--readonly, -r : Prevent opened files from writing
--filetype [name], -f [name] : Set the file type of files opened
--stdin : Reads file from the stdin
+ --config-assist : Activate the configuration assistant
EXAMPLES:
ox
@@ -27,7 +28,8 @@ EXAMPLES:
ox /home/user/docs/test.txt
ox -c config.lua test.txt
ox -r -c ~/.config/.oxrc -f Lua my_file.lua
- tree | ox -r --stdin\
+ tree | ox -r --stdin
+ ox --config-assist\
";
/// Read from the standard input
@@ -44,6 +46,7 @@ pub struct CommandLineInterfaceFlags {
pub version: bool,
pub read_only: bool,
pub stdin: bool,
+ pub config_assist: bool,
}
/// Struct to help with starting ox
@@ -70,6 +73,7 @@ impl CommandLineInterface {
version: j.contains(["-v", "--version"]),
read_only: j.contains(["-r", "--readonly"]),
stdin: j.contains("--stdin"),
+ config_assist: j.contains("--config-assist"),
},
file_type: j.option_arg::(filetype.clone()),
config_path: j
diff --git a/src/config/assistant.rs b/src/config/assistant.rs
new file mode 100644
index 00000000..173bb50e
--- /dev/null
+++ b/src/config/assistant.rs
@@ -0,0 +1,689 @@
+use crate::cli::VERSION;
+/// Code for the configuration set-up assistant
+use crate::config::{Colors, Indentation, SyntaxHighlighting};
+use crate::error::Result;
+use crossterm::style::{SetBackgroundColor as Bg, SetForegroundColor as Fg};
+use mlua::prelude::*;
+use std::cell::RefCell;
+use std::io::Write;
+use std::rc::Rc;
+//use crate::config::Color;
+//use std::collections::HashMap;
+
+pub const TROPICAL: &str = include_str!("../themes/tropical.lua");
+pub const GALAXY: &str = include_str!("../themes/galaxy.lua");
+pub const TRANSPARENT: &str = include_str!("../themes/transparent.lua");
+
+#[macro_export]
+macro_rules! gets {
+ () => {{
+ let mut s = std::string::String::new();
+ std::io::stdin().read_line(&mut s).unwrap();
+ s.trim_end_matches(&['\n', '\r'][..]).to_owned()
+ }};
+ ( $($args:tt)* ) => {{
+ use std::io::Write;
+ print!("{}", format_args!($($args)*));
+ std::io::stdout().flush().unwrap();
+ $crate::gets!()
+ }};
+}
+
+const TITLE: &str = r"
+ ___ ____ __ _ _ _ _ _
+ / _ \__ __ / ___|___ _ __ / _(_) __ _ / \ ___ ___(_)___| |_ __ _ _ __ | |_
+| | | \ \/ / | | / _ \| '_ \| |_| |/ _` | / _ \ / __/ __| / __| __/ _` | '_ \| __|
+| |_| |> < | |__| (_) | | | | _| | (_| | / ___ \\__ \__ \ \__ \ || (_| | | | | |_
+ \___//_/\_\ \____\___/|_| |_|_| |_|\__, | /_/ \_\___/___/_|___/\__\__,_|_| |_|\__|
+ |___/
+";
+
+const NO_CONFIG_MESSAGE: &str = r"
+Thank you for installing Ox
+We noticed you don't have a configuration file.
+This set-up process will help you customise and configure Ox.
+This way, you'll have a better user experience out of the box.
+";
+
+const INTRODUCTION: &str = r"
+Welcome to the configuration assistant for the Ox Editor.
+This is a tool that will help get Ox set up for you.
+It will take no more than 5 minutes and the config assistant will not show again after set-up.
+You can always re-access this tool using `ox --config-assist`
+
+";
+
+const PLUGIN_LIST: &str = r"
+Ox has an ecosystem of plug-ins that you can make use of, they are as follows:
+
+──────────────────── Code Helpers ────────────────────
+AutoIndent - A plug-in that will insert and remove code indentation automatically
+Pairs - A plug-in that will insert end brackets and end quotes automatically
+
+─────────────────── Web Development ──────────────────
+Emmet - A neat language to help you write HTML quickly - requires python and the py-emmet module
+Live HTML - Start a web server that previews your HTML site as you write the code - requires python and the Flask module
+
+────────── Integration with Existing Tools ───────────
+DiscordRPC - Have Ox interact with Discord and show your programming activity - requires python and the discord-rpc module
+Git - View and manage your git repository - requires git to be installed
+
+─────────────────── Miscellaneous ────────────────────
+Pomodoro - A timer that helps you track your periods of work and breaks
+Todo - Makes .todo files interactive todo lists
+Typing Speed - Shows the rough speed that you're typing in the status line
+Update Notification - Warns you if there is a new version of Ox - requires curl to be installed on unix based systems\n
+";
+
+#[derive(PartialEq)]
+pub enum Theme {
+ Tropical,
+ Galaxy,
+ Transparent,
+ Default,
+ //Custom(HashMap),
+}
+
+impl Theme {
+ pub fn to_config(&self) -> String {
+ match self {
+ Self::Tropical => TROPICAL,
+ Self::Galaxy => GALAXY,
+ Self::Transparent => TRANSPARENT,
+ Self::Default => "",
+ }
+ .to_string()
+ }
+}
+
+#[derive(PartialEq, Debug)]
+pub enum Plugin {
+ AutoIndent,
+ Pairs,
+ DiscordRPC,
+ Emmet,
+ Git,
+ LiveHTML,
+ Pomodoro,
+ Todo,
+ TypingSpeed,
+ UpdateNotification,
+}
+
+impl Plugin {
+ pub fn to_config(&self) -> String {
+ format!(
+ "load_plugin(\"{}\")\n",
+ match self {
+ Self::AutoIndent => "autoindent.lua",
+ Self::Pairs => "pairs.lua",
+ Self::DiscordRPC => "discord_rpc.lua",
+ Self::Emmet => "emmet.lua",
+ Self::Git => "git.lua",
+ Self::LiveHTML => "live_html.lua",
+ Self::Pomodoro => "pomodoro.lua",
+ Self::Todo => "todo.lua",
+ Self::TypingSpeed => "typing_speed.lua",
+ Self::UpdateNotification => "update_notification.lua",
+ }
+ )
+ }
+}
+
+#[allow(clippy::struct_excessive_bools)]
+pub struct Assistant {
+ pub theme: Theme,
+ pub indentation: Indentation,
+ pub tab_width: usize,
+ pub mouse: bool,
+ pub scroll_sensitivity: usize,
+ pub cursor_wrap: bool,
+ pub line_numbers: bool,
+ pub line_number_padding: (usize, usize),
+ pub icons: bool,
+ pub tab_line: bool,
+ pub greeting_message: bool,
+ pub plugins: Vec,
+}
+
+impl Default for Assistant {
+ fn default() -> Self {
+ Self {
+ // Colours and theme
+ theme: Theme::Default,
+ // Document
+ indentation: Indentation::Tabs,
+ tab_width: 4,
+ // Line Numbers
+ line_numbers: true,
+ line_number_padding: (1, 1),
+ // Tab Line
+ tab_line: true,
+ // Greeting Message
+ greeting_message: true,
+ // Mouse and Cursor Behaviour
+ mouse: true,
+ scroll_sensitivity: 2,
+ cursor_wrap: true,
+ // Plug-ins
+ plugins: vec![Plugin::AutoIndent, Plugin::Pairs],
+ // Misc
+ icons: false,
+ }
+ }
+}
+
+impl Assistant {
+ /// Run the configuration assistant
+ pub fn run(because_no_config: bool) -> Result<()> {
+ println!("{TITLE}");
+ if because_no_config {
+ println!("{NO_CONFIG_MESSAGE}");
+ }
+ println!("{INTRODUCTION}");
+ if Self::confirmation("Do you wish to set-up the editor?", true) {
+ let mut result = Self::default();
+ // Theme
+ println!("Let's begin with what theme you'd like to use\n\n");
+ // Prepare demonstration
+ Self::demonstrate_themes()?;
+ let choice = Self::options(
+ "Please choose which theme you'd like",
+ &["default", "tropical", "galaxy", "transparent"],
+ "default",
+ );
+ result.theme = match choice.as_str() {
+ "default" => Theme::Default,
+ "tropical" => Theme::Tropical,
+ "galaxy" => Theme::Galaxy,
+ "transparent" => Theme::Transparent,
+ _ => unreachable!(),
+ };
+ // Document
+ println!("Great choice, now let's move onto indentation\n");
+ result.indentation = Self::options(
+ "Please choose how you'd like to represent indentation",
+ &["spaces", "tabs"],
+ "tabs",
+ )
+ .into();
+ result.tab_width = if result.indentation == Indentation::Tabs {
+ Self::integer("How wide should tabs be rendered as", 4)
+ } else {
+ Self::integer("How many spaces should make up 1 indent", 4)
+ };
+ // Line Numbers
+ println!("Great, now for deciding which parts of the editor should be visible\n");
+ result.line_numbers =
+ Self::confirmation("Would you like line numbers to be visible", true);
+ if result.line_numbers {
+ result.line_number_padding = (
+ Self::integer(
+ "How much space should there be on the left hand side of the line numbers",
+ 1,
+ ),
+ Self::integer(
+ "How much space should there be on the right hand side of the line numbers",
+ 1,
+ ),
+ );
+ }
+ // Tab line
+ result.tab_line = Self::confirmation("Would you like the tab line to be visible", true);
+ // Greeting message
+ result.greeting_message = Self::confirmation(
+ "Would you like the greeting message to be visible on start-up",
+ true,
+ );
+ // Mouse and Cursor
+ println!("Now for the mouse and cursor behaviour\n");
+ result.mouse = Self::confirmation(
+ "Would you like to use your mouse cursor in the editor",
+ true,
+ );
+ result.scroll_sensitivity = Self::integer(
+ "How sensitive should scrolling be, 1 = least sensitive, 5 = very sensitive",
+ 2,
+ );
+ result.cursor_wrap = Self::confirmation(
+ "Would you like the cursor to wrap around when at the edge of a line",
+ true,
+ );
+ // Icons
+ println!("Ox has support for icons, which can enhance the UI, if you choose to enable them, ensure you install nerd fonts\n");
+ result.icons =
+ Self::confirmation("Would you like to enable icons, yes is recommended", false);
+ // Plug-Ins
+ Self::ask_plugins(&mut result);
+ // Create the configuration file (and print it)
+ println!("\nSet-up is complete!");
+ if !because_no_config {
+ println!("WARNING: config file already exists, it will be backed-up to ~/.oxrc-backup if you write");
+ }
+ let result = result.to_config();
+ if Self::confirmation(
+ "Would you like to write the configuration file?",
+ because_no_config,
+ ) {
+ let config_path = format!("{}/.oxrc", shellexpand::tilde("~"));
+ let backup_path = format!("{}/.oxrc-backup", shellexpand::tilde("~"));
+ if !because_no_config {
+ let _ = std::fs::rename(config_path.clone(), backup_path);
+ }
+ let mut file = std::fs::OpenOptions::new()
+ .write(true)
+ .create(true)
+ .truncate(true)
+ .open(config_path)?;
+ file.write_all(result.as_bytes())?;
+ } else {
+ println!("Below is your newly generated configuration file:\n\n");
+ println!("{result}");
+ }
+ }
+ Ok(())
+ }
+
+ pub fn confirmation(msg: &str, default: bool) -> bool {
+ let mut response = "#####################".to_string();
+ while response != "y" && response != "n" && !response.is_empty() {
+ response = gets!(
+ "{msg}, default is {} (y/n)\n> ",
+ if default { "yes" } else { "no" }
+ )
+ .to_lowercase();
+ }
+ println!();
+ if response.is_empty() {
+ default
+ } else {
+ response == "y"
+ }
+ }
+
+ pub fn options(msg: &str, options: &[&str], default: &str) -> String {
+ let options: Vec = options
+ .iter()
+ .map(std::string::ToString::to_string)
+ .collect();
+ let mut response = "#####################".to_string();
+ while !options.contains(&response) && !response.is_empty() {
+ response =
+ gets!("{msg}, default is {default} ({})\n> ", options.join("/")).to_lowercase();
+ }
+ println!();
+ if response.is_empty() {
+ default.to_string()
+ } else {
+ response
+ }
+ }
+
+ pub fn integer(msg: &str, default: usize) -> usize {
+ let mut response = "#####################".to_string();
+ while response.parse::().is_err() && !response.is_empty() {
+ response = gets!("{msg} (enter a number, default: {default})\n> ").to_lowercase();
+ }
+ println!();
+ if response.is_empty() {
+ default
+ } else {
+ response.parse::().unwrap()
+ }
+ }
+
+ pub fn ask_plugins(result: &mut Self) {
+ println!("{PLUGIN_LIST}");
+ let mut adding = String::new();
+ while adding != "exit" {
+ println!("Enabled plug-ins: {:?}\n", result.plugins);
+ adding = Self::options(
+ "Enter the name of a plug-in you'd like to enable / disable",
+ &[
+ "autoindent",
+ "pairs",
+ "emmet",
+ "live_html",
+ "discord_rpc",
+ "git",
+ "pomodoro",
+ "todo",
+ "typing_speed",
+ "update_notification",
+ "exit",
+ ],
+ "exit",
+ );
+ let plugin = match adding.as_str() {
+ "autoindent" => Plugin::AutoIndent,
+ "pairs" => Plugin::Pairs,
+ "emmet" => Plugin::Emmet,
+ "live_html" => Plugin::LiveHTML,
+ "discord_rpc" => Plugin::DiscordRPC,
+ "git" => Plugin::Git,
+ "pomodoro" => Plugin::Pomodoro,
+ "todo" => Plugin::Todo,
+ "typing_speed" => Plugin::TypingSpeed,
+ "update_notification" => Plugin::UpdateNotification,
+ _ => continue,
+ };
+ if result.plugins.contains(&plugin) {
+ result.plugins.retain(|p| *p != plugin);
+ } else {
+ result.plugins.push(plugin);
+ }
+ }
+ }
+
+ pub fn demonstrate_themes() -> Result<()> {
+ println!(
+ "{}",
+ Self::demonstrate_theme_row(&["default", "transparent"])?
+ );
+ println!("{}", Self::demonstrate_theme_row(&["tropical", "galaxy"])?);
+ Ok(())
+ }
+
+ pub fn demonstrate_theme_row(include: &[&str]) -> Result {
+ // Gather the list of theme previews
+ let mut themes: Vec> = vec![];
+ for name in include {
+ let code = match *name {
+ "default" => "",
+ "tropical" => TROPICAL,
+ "galaxy" => GALAXY,
+ "transparent" => TRANSPARENT,
+ _ => unreachable!(),
+ };
+ let theme = Self::demonstrate_theme(name, code)?
+ .split('\n')
+ .map(std::string::ToString::to_string)
+ .collect();
+ themes.push(theme);
+ }
+ // Put into row format
+ let mut result = String::new();
+ let mut at = 0;
+ while at < 13 {
+ for theme in &themes {
+ result += &format!("{} ", theme[at]);
+ }
+ result += "\n";
+ at += 1;
+ }
+ // Return the result
+ Ok(result)
+ }
+
+ pub fn demonstrate_theme(name: &str, code: &str) -> Result {
+ // Create an environment to capture all the values
+ let lua = Lua::new();
+ let colors = Rc::new(RefCell::new(Colors::default()));
+ let syntax_highlighting = Rc::new(RefCell::new(SyntaxHighlighting::default()));
+ lua.globals().set("syntax", syntax_highlighting.clone())?;
+ lua.globals().set("colors", colors.clone())?;
+ // Access all the values
+ lua.load(code).exec()?;
+ // Gather the editor colours
+ let col = colors.borrow();
+ let editor = format!(
+ "{}{}",
+ Fg(col.editor_fg.to_color()?),
+ Bg(col.editor_bg.to_color()?)
+ );
+ let reset = format!(
+ "{}{}",
+ Fg(crossterm::style::Color::Reset),
+ Bg(crossterm::style::Color::Reset)
+ );
+ let active_tab = format!(
+ "{}{}",
+ Fg(col.tab_active_fg.to_color()?),
+ Bg(col.tab_active_bg.to_color()?)
+ );
+ let inactive_tab = format!(
+ "{}{}",
+ Fg(col.tab_inactive_fg.to_color()?),
+ Bg(col.tab_inactive_bg.to_color()?)
+ );
+ let line_number = format!(
+ "{}{}",
+ Fg(col.line_number_fg.to_color()?),
+ Bg(col.line_number_bg.to_color()?)
+ );
+ let status_line = format!(
+ "{}{}",
+ Fg(col.status_fg.to_color()?),
+ Bg(col.status_bg.to_color()?)
+ );
+ let error = format!(
+ "{}{}",
+ Fg(col.error_fg.to_color()?),
+ Bg(col.error_bg.to_color()?)
+ );
+ let warning = format!(
+ "{}{}",
+ Fg(col.warning_fg.to_color()?),
+ Bg(col.warning_bg.to_color()?)
+ );
+ let info = format!(
+ "{}{}",
+ Fg(col.info_fg.to_color()?),
+ Bg(col.info_bg.to_color()?)
+ );
+ // Gather syntax highlighting colours
+ let string = Fg(syntax_highlighting.borrow().get_theme("string")?);
+ let comment = Fg(syntax_highlighting.borrow().get_theme("comment")?);
+ let digit = Fg(syntax_highlighting.borrow().get_theme("digit")?);
+ let keyword = Fg(syntax_highlighting.borrow().get_theme("keyword")?);
+ let character = Fg(syntax_highlighting.borrow().get_theme("character")?);
+ let type_syn = Fg(syntax_highlighting.borrow().get_theme("type")?);
+ let function = Fg(syntax_highlighting.borrow().get_theme("function")?);
+ let macro_syn = Fg(syntax_highlighting.borrow().get_theme("macro")?);
+ let block = Fg(syntax_highlighting.borrow().get_theme("block")?);
+ let namespace = Fg(syntax_highlighting.borrow().get_theme("namespace")?);
+ let header = Fg(syntax_highlighting.borrow().get_theme("header")?);
+ let struct_syn = Fg(syntax_highlighting.borrow().get_theme("struct")?);
+ let operator = Fg(syntax_highlighting.borrow().get_theme("operator")?);
+ let boolean = Fg(syntax_highlighting.borrow().get_theme("boolean")?);
+ let reference = Fg(syntax_highlighting.borrow().get_theme("reference")?);
+ let tag = Fg(syntax_highlighting.borrow().get_theme("tag")?);
+ let heading = Fg(syntax_highlighting.borrow().get_theme("heading")?);
+ let link = Fg(syntax_highlighting.borrow().get_theme("link")?);
+ let bold = Fg(syntax_highlighting.borrow().get_theme("bold")?);
+ let italic = Fg(syntax_highlighting.borrow().get_theme("italic")?);
+ let insertion = Fg(syntax_highlighting.borrow().get_theme("insertion")?);
+ let deletion = Fg(syntax_highlighting.borrow().get_theme("deletion")?);
+ // Render the preview
+ let name = format!(" {name} ");
+ Ok(format!("{name:─^47}
+{editor}┌─────────────────────────────────────────────┐{reset}
+{editor}│{inactive_tab} Inactive Tab |{active_tab} Active Tab {inactive_tab}| {editor}│{reset}
+{editor}│{line_number} 1 │{editor}{function}print{editor}({string}\"hello\" {operator}+ {digit}3 {operator}+ {boolean}true {operator}+ {character}'c'{editor}); │{reset}
+{editor}│{line_number} 2 │{editor}{keyword}let {editor}var{operator}: {type_syn}Type {operator}= {reference}&{struct_syn}Object{editor}({namespace}name::space{editor}); │{reset}
+{editor}│{line_number} 3 │{editor}{tag} {comment}// Comment{editor} │{reset}
+{editor}│{line_number} 4 │{editor}{header}import {editor}random; │{reset}
+{editor}│{line_number} 5 │{editor}{macro_syn}macro!{editor}(); {insertion}+ insertion {deletion}- deletion {editor}│{reset}
+{editor}│{line_number} 6 │{editor}{heading}# Title {italic}*italic* {bold}**bold** {block}`code`{editor} │{reset}
+{editor}│{line_number} 7 │{editor}{link}[link](example.com){editor} │{reset}
+{editor}│{status_line} Status Line {editor}│{reset}
+{editor}│{error} Error {warning} Warning {info} Information {editor}│{reset}
+{editor}└─────────────────────────────────────────────┘{reset}"))
+ }
+
+ /// Turn the configuration assistant details into a lua file
+ pub fn to_config(&self) -> String {
+ let mut result = String::new();
+ let (sections, fields) = self.diff();
+ // Comment at the top
+ result += &format!(
+ "-- Configuration generated for Ox {VERSION} by the configuration assistant --\n"
+ );
+ // Configuration of colours and theme
+ if sections.contains(&"theme") {
+ result += &self.theme.to_config();
+ }
+ // Configuration of document
+ if sections.contains(&"document") {
+ result += "\n-- Document Configuration --\n";
+ if fields.contains(&"indentation") {
+ result += &format!("document.indentation = '{}'\n", self.indentation);
+ }
+ if fields.contains(&"tab_width") {
+ result += &format!("document.tab_width = {}\n", self.tab_width);
+ }
+ }
+ // Configuration of line numbers
+ if sections.contains(&"line_number") {
+ result += "\n-- Line Number Configuration --\n";
+ if fields.contains(&"line_numbers") {
+ result += &format!("line_numbers.enabled = {}\n", self.line_numbers);
+ }
+ if fields.contains(&"line_number_padding") {
+ result += &format!(
+ "line_numbers.padding_left = {}\n",
+ self.line_number_padding.0
+ );
+ result += &format!(
+ "line_numbers.padding_right = {}\n",
+ self.line_number_padding.1
+ );
+ }
+ }
+ // Configuration of tab line
+ if sections.contains(&"tab_line") {
+ result += "\n-- Tab Line Configuration --\n";
+ result += &format!("tab_line.enabled = {}\n", self.tab_line);
+ let mut format = " {file_name}{modified} ".to_string();
+ let mut format_changed = false;
+ if self.icons {
+ format = format.replace("{file_name}", "{icon} {file_name}");
+ format_changed = true;
+ }
+ if self.plugins.contains(&Plugin::Git) {
+ format = format.replace("{modified}", "{modified} {git_status}");
+ format_changed = true;
+ }
+ if format_changed {
+ result += &format!("tab_line.format = '{format}'\n");
+ }
+ }
+ // Configuration of status line
+ if sections.contains(&"status_line") {
+ result += "\n-- Status Line Configuration --\n";
+ let mut left = " {file_name}{modified} │ {file_type} │".to_string();
+ let mut right = "│ {cursor_y} / {line_count} {cursor_x} ".to_string();
+ // Handle file type icons
+ if self.icons {
+ left = left.replace("{file_type}", "{icon} {file_type}");
+ }
+ // Handle git plug-in
+ if self.plugins.contains(&Plugin::Git) && self.icons {
+ right = format!("│ {{git_branch}} {right}");
+ } else if self.plugins.contains(&Plugin::Git) && !self.icons {
+ right = format!("│ {{git_branch}} {right}");
+ }
+ // Handle typing speed plug-in
+ if self.plugins.contains(&Plugin::TypingSpeed) {
+ right = format!("│ {{typing_speed_show}} {right}");
+ }
+ // Handle pomodoro plug-in
+ if self.plugins.contains(&Plugin::Pomodoro) {
+ left = format!("{left} {{pomodoro_show}} │");
+ }
+ result += &format!("status_line.parts = {{\n\t'{left}',\n\t'{right}',\n}}\n");
+ }
+ // Configuration of greeting message
+ if sections.contains(&"greeting_message") {
+ result += "\n-- Greeting Message Configuration --\n";
+ result += &format!("greeting_message.enabled = {}\n", self.greeting_message);
+ }
+ // Configuration of mouse and cursor behaviour
+ if sections.contains(&"cursors") {
+ result += "\n-- Cursor Configuration --\n";
+ if fields.contains(&"mouse") {
+ result += &format!("terminal.mouse_enabled = {}\n", self.mouse);
+ }
+ if fields.contains(&"scroll_sensitivity") {
+ result += &format!("terminal.scroll_amount = {}\n", self.scroll_sensitivity);
+ }
+ if fields.contains(&"cursor_wrap") {
+ result += &format!("document.wrap_cursor = {}\n", self.cursor_wrap);
+ }
+ }
+ // Configuration of plug-ins
+ result += "\n-- Load Plug-Ins --\n";
+ for plugin in &self.plugins {
+ result += &plugin.to_config();
+ }
+ // Ready to go
+ result
+ }
+
+ /// Find the difference between the default configuration and this one
+ pub fn diff(&self) -> (Vec<&str>, Vec<&str>) {
+ let def = Self::default();
+ let fields = vec![
+ ("theme", self.theme != def.theme),
+ ("indentation", self.indentation != def.indentation),
+ ("line_numbers", self.line_numbers != def.line_numbers),
+ ("tab_line", self.tab_line != def.tab_line),
+ (
+ "greeting_message",
+ self.greeting_message != def.greeting_message,
+ ),
+ ("mouse", self.mouse != def.mouse),
+ ("cursor_wrap", self.cursor_wrap != def.cursor_wrap),
+ ("icons", self.icons != def.icons),
+ (
+ "line_number_padding",
+ self.line_number_padding != def.line_number_padding,
+ ),
+ (
+ "scroll_sensitivity",
+ self.scroll_sensitivity != def.scroll_sensitivity,
+ ),
+ ("tab_width", self.tab_width != def.tab_width),
+ ];
+ let fields = fields
+ .iter()
+ .filter_map(|(name, differs)| if *differs { Some(*name) } else { None })
+ .collect::>();
+ let sections = [
+ ("theme", fields.contains(&"theme")),
+ (
+ "document",
+ fields.contains(&"indentation") || fields.contains(&"tab_width"),
+ ),
+ (
+ "line_numbers",
+ fields.contains(&"line_numbers") || fields.contains(&"line_number_padding"),
+ ),
+ (
+ "tab_line",
+ fields.contains(&"tab_line")
+ || fields.contains(&"icons")
+ || self.plugins.contains(&Plugin::Git),
+ ),
+ (
+ "status_line",
+ fields.contains(&"icons")
+ || self.plugins.contains(&Plugin::Git)
+ || self.plugins.contains(&Plugin::Pomodoro)
+ || self.plugins.contains(&Plugin::TypingSpeed),
+ ),
+ ("greeting_message", fields.contains(&"greeting_message")),
+ (
+ "cursors",
+ fields.contains(&"mouse")
+ || fields.contains(&"scroll_sensitivity")
+ || fields.contains(&"cursor_wrap"),
+ ),
+ ];
+ let sections = sections
+ .iter()
+ .filter_map(|(name, differs)| if *differs { Some(*name) } else { None })
+ .collect::>();
+ (sections, fields)
+ }
+}
diff --git a/src/config/colors.rs b/src/config/colors.rs
index 053b6dc3..333883f1 100644
--- a/src/config/colors.rs
+++ b/src/config/colors.rs
@@ -37,31 +37,31 @@ pub struct Colors {
impl Default for Colors {
fn default() -> Self {
Self {
- editor_bg: Color::Black,
- editor_fg: Color::Black,
+ editor_bg: Color::Rgb(41, 41, 61),
+ editor_fg: Color::Rgb(255, 255, 255),
- status_bg: Color::Black,
- status_fg: Color::Black,
+ status_bg: Color::Rgb(59, 59, 84),
+ status_fg: Color::Rgb(35, 240, 144),
- highlight: Color::Black,
+ highlight: Color::Rgb(35, 240, 144),
- line_number_fg: Color::Black,
- line_number_bg: Color::Black,
+ line_number_fg: Color::Rgb(65, 65, 98),
+ line_number_bg: Color::Rgb(41, 41, 61),
- tab_active_fg: Color::Black,
- tab_active_bg: Color::Black,
- tab_inactive_fg: Color::Black,
- tab_inactive_bg: Color::Black,
+ tab_active_fg: Color::Rgb(255, 255, 255),
+ tab_active_bg: Color::Rgb(41, 41, 61),
+ tab_inactive_fg: Color::Rgb(255, 255, 255),
+ tab_inactive_bg: Color::Rgb(59, 59, 84),
- info_bg: Color::Black,
- info_fg: Color::Black,
- warning_bg: Color::Black,
- warning_fg: Color::Black,
- error_bg: Color::Black,
- error_fg: Color::Black,
+ info_bg: Color::Rgb(41, 41, 61),
+ info_fg: Color::Rgb(99, 162, 255),
+ warning_bg: Color::Rgb(41, 41, 61),
+ warning_fg: Color::Rgb(255, 182, 99),
+ error_bg: Color::Rgb(41, 41, 61),
+ error_fg: Color::Rgb(255, 100, 100),
- selection_fg: Color::White,
- selection_bg: Color::Blue,
+ selection_fg: Color::Rgb(41, 41, 61),
+ selection_bg: Color::Rgb(41, 41, 61),
}
}
}
diff --git a/src/config/highlighting.rs b/src/config/highlighting.rs
index d462b958..e4c7e426 100644
--- a/src/config/highlighting.rs
+++ b/src/config/highlighting.rs
@@ -10,13 +10,51 @@ use super::Color;
type BoundedInterpArgs = (String, String, String, String, String, bool);
/// For storing configuration information related to syntax highlighting
-#[derive(Debug, Default)]
+#[derive(Debug)]
#[allow(clippy::module_name_repetitions)]
pub struct SyntaxHighlighting {
pub theme: HashMap,
pub user_rules: HashMap,
}
+impl Default for SyntaxHighlighting {
+ fn default() -> Self {
+ let mut theme = HashMap::default();
+ theme.insert("string".to_string(), Color::Rgb(39, 222, 145));
+ theme.insert("comment".to_string(), Color::Rgb(113, 113, 169));
+ theme.insert("digit".to_string(), Color::Rgb(40, 198, 232));
+ theme.insert("keyword".to_string(), Color::Rgb(134, 76, 232));
+ theme.insert("attribute".to_string(), Color::Rgb(40, 198, 232));
+ theme.insert("character".to_string(), Color::Rgb(40, 198, 232));
+ theme.insert("type".to_string(), Color::Rgb(47, 141, 252));
+ theme.insert("function".to_string(), Color::Rgb(47, 141, 252));
+ theme.insert("header".to_string(), Color::Rgb(40, 198, 232));
+ theme.insert("macro".to_string(), Color::Rgb(223, 52, 249));
+ theme.insert("namespace".to_string(), Color::Rgb(47, 141, 252));
+ theme.insert("struct".to_string(), Color::Rgb(47, 141, 252));
+ theme.insert("operator".to_string(), Color::Rgb(113, 113, 169));
+ theme.insert("boolean".to_string(), Color::Rgb(86, 217, 178));
+ theme.insert("table".to_string(), Color::Rgb(47, 141, 252));
+ theme.insert("reference".to_string(), Color::Rgb(134, 76, 232));
+ theme.insert("tag".to_string(), Color::Rgb(40, 198, 232));
+ theme.insert("heading".to_string(), Color::Rgb(47, 141, 252));
+ theme.insert("link".to_string(), Color::Rgb(223, 52, 249));
+ theme.insert("key".to_string(), Color::Rgb(223, 52, 249));
+ theme.insert("quote".to_string(), Color::Rgb(113, 113, 169));
+ theme.insert("bold".to_string(), Color::Rgb(40, 198, 232));
+ theme.insert("italic".to_string(), Color::Rgb(40, 198, 232));
+ theme.insert("block".to_string(), Color::Rgb(40, 198, 232));
+ theme.insert("image".to_string(), Color::Rgb(40, 198, 232));
+ theme.insert("list".to_string(), Color::Rgb(86, 217, 178));
+ theme.insert("insertion".to_string(), Color::Rgb(39, 222, 145));
+ theme.insert("deletion".to_string(), Color::Rgb(255, 100, 100));
+ Self {
+ theme,
+ user_rules: HashMap::default(),
+ }
+ }
+}
+
impl SyntaxHighlighting {
/// Get a colour from the theme
pub fn get_theme(&self, name: &str) -> Result {
diff --git a/src/config/interface.rs b/src/config/interface.rs
index 064d4f81..df876da0 100644
--- a/src/config/interface.rs
+++ b/src/config/interface.rs
@@ -386,18 +386,23 @@ impl StatusLine {
}
impl LuaUserData for StatusLine {
- fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
- methods.add_method_mut("clear", |_, status_line, ()| {
- status_line.parts.clear();
- Ok(())
+ fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
+ fields.add_field_method_get("parts", |lua, this| {
+ let parts = lua.create_table()?;
+ for (i, part) in this.parts.iter().enumerate() {
+ parts.set(i + 1, part.clone())?;
+ }
+ Ok(parts)
});
- methods.add_method_mut("add_part", |_, status_line, part| {
- status_line.parts.push(part);
+ fields.add_field_method_set("parts", |_, this, value: LuaTable| {
+ let mut result = vec![];
+ for item in value.pairs::() {
+ let (_, part) = item?;
+ result.push(part);
+ }
+ this.parts = result;
Ok(())
});
- }
-
- fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("alignment", |_, this| {
let alignment: String = this.alignment.clone().into();
Ok(alignment)
diff --git a/src/config/mod.rs b/src/config/mod.rs
index aa334db4..3578f22a 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -10,6 +10,7 @@ use std::{
rc::Rc,
};
+mod assistant;
mod colors;
mod editor;
mod highlighting;
@@ -17,6 +18,7 @@ mod interface;
mod keys;
mod tasks;
+pub use assistant::Assistant;
pub use colors::{Color, Colors};
pub use highlighting::SyntaxHighlighting;
pub use interface::{GreetingMessage, HelpMessage, LineNumbers, StatusLine, TabLine, Terminal};
@@ -145,29 +147,20 @@ impl Config {
}
/// Actually take the configuration file, open it and interpret it
- pub fn read(&mut self, path: &str, lua: &Lua) -> Result<()> {
+ pub fn read(path: &str, lua: &Lua) -> Result<()> {
// Load the default config to start with
lua.load(DEFAULT_CONFIG).exec()?;
// Reset plugin status based on built-in configuration file
lua.load("plugins = {}").exec()?;
lua.load("builtins = {}").exec()?;
- // Judge pre-user config state
- let status_parts = self.status_line.borrow().parts.len();
-
// Attempt to read config file from home directory
+ let user_provided = Self::get_user_provided_config(path);
let mut user_provided_config = false;
- if let Ok(path) = shellexpand::full(&path) {
- if let Ok(config) = std::fs::read_to_string(path.to_string()) {
- // Update configuration with user-defined values
- lua.load(config).exec()?;
- user_provided_config = true;
- }
- }
-
- // Remove any default values if necessary
- if self.status_line.borrow().parts.len() > status_parts {
- self.status_line.borrow_mut().parts.drain(0..status_parts);
+ if let Some(config) = user_provided {
+ // Load in user-defined configuration file
+ lua.load(config).exec()?;
+ user_provided_config = true;
}
// Determine whether or not to load built-in plugins
@@ -188,6 +181,16 @@ impl Config {
}
}
+ /// Read the user-provided config
+ pub fn get_user_provided_config(path: &str) -> Option {
+ if let Ok(path) = shellexpand::full(&path) {
+ if let Ok(config) = std::fs::read_to_string(path.to_string()) {
+ return Some(config);
+ }
+ }
+ None
+ }
+
/// Decide whether to load a built-in plugin
pub fn load_bi(name: &str, user_provided_config: bool, lua: &Lua) -> bool {
if user_provided_config {
diff --git a/src/editor/mod.rs b/src/editor/mod.rs
index 46b47fb4..f1f778c8 100644
--- a/src/editor/mod.rs
+++ b/src/editor/mod.rs
@@ -313,7 +313,7 @@ impl Editor {
/// Load the configuration values
pub fn load_config(&mut self, path: &str, lua: &Lua) -> Option {
self.config_path = path.to_string();
- let result = self.config.read(path, lua);
+ let result = Config::read(path, lua);
// Display any warnings if the user configuration couldn't be found
match result {
Ok(()) => (),
diff --git a/src/main.rs b/src/main.rs
index e2a1ca4c..cd93af7e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,8 +8,8 @@ mod ui;
use cli::CommandLineInterface;
use config::{
- key_to_string, run_key, run_key_before, PLUGIN_BOOTSTRAP, PLUGIN_MANAGER, PLUGIN_NETWORKING,
- PLUGIN_RUN,
+ key_to_string, run_key, run_key_before, Assistant, Config, PLUGIN_BOOTSTRAP, PLUGIN_MANAGER,
+ PLUGIN_NETWORKING, PLUGIN_RUN,
};
use crossterm::event::Event as CEvent;
use editor::{Editor, FileTypes};
@@ -32,6 +32,15 @@ fn main() {
// Handle help and version options
cli.basic_options();
+ // Activate configuration assistant if applicable
+ let no_config = Config::get_user_provided_config(&cli.config_path).is_none();
+ if no_config || cli.flags.config_assist {
+ if let Err(err) = Assistant::run(no_config) {
+ panic!("{err:?}");
+ }
+ }
+
+ // Run the editor
let result = run(&cli);
if let Err(err) = result {
panic!("{err:?}");
diff --git a/config/catppuccin-mocha.lua b/src/themes/galaxy.lua
similarity index 73%
rename from config/catppuccin-mocha.lua
rename to src/themes/galaxy.lua
index 87afdeaa..40f39ea3 100644
--- a/config/catppuccin-mocha.lua
+++ b/src/themes/galaxy.lua
@@ -1,16 +1,9 @@
--- Define user-defined commands
-commands = {
- ["reload"] = function(arguments)
- editor:reload_config()
- editor:display_info("Configuration file and plugins reloaded")
- end,
-}
-- Pallette --
black = '#1e1e2e'
-darkgrey = '#24273a'
-lightgrey = '#303446'
-verylightgrey = '#7f849c'
+grey1 = '#24273a'
+grey2 = '#303446'
+grey3 = '#7f849c'
white = '#cdd6f4'
brown = '#f2cdcd'
red = '#f38ba8'
@@ -25,17 +18,17 @@ pink = '#f5c2e7'
-- Configure Colours --
colors.editor_bg = black
colors.editor_fg = white
-colors.line_number_fg = lightgrey
+colors.line_number_fg = grey2
colors.line_number_bg = black
-colors.status_bg = darkgrey
+colors.status_bg = grey1
colors.status_fg = purple
colors.highlight = purple
-colors.tab_inactive_bg = darkgrey
+colors.tab_inactive_bg = grey1
colors.tab_inactive_fg = white
-colors.tab_active_bg = lightgrey
+colors.tab_active_bg = grey2
colors.tab_active_fg = purple
colors.info_bg = black
@@ -45,12 +38,12 @@ colors.warning_fg = yellow
colors.error_bg = black
colors.error_fg = red
-colors.selection_bg = darkgrey
+colors.selection_bg = grey1
colors.selection_fg = lightblue
-- Configure Syntax Highlighting Colours --
syntax:set("string", green) -- Strings, bright green
-syntax:set("comment", verylightgrey) -- Comments, light purple/gray
+syntax:set("comment", grey3) -- Comments, light purple/gray
syntax:set("digit", red) -- Digits, cyan
syntax:set("keyword", purple) -- Keywords, vibrant pink
syntax:set("attribute", lightblue) -- Attributes, cyan
@@ -61,7 +54,7 @@ syntax:set("header", lightblue) -- Headers, cyan
syntax:set("macro", red) -- Macros, red
syntax:set("namespace", darkblue) -- Namespaces, light purple
syntax:set("struct", pink) -- Structs, classes, and enums, light purple
-syntax:set("operator", verylightgrey) -- Operators, light purple/gray
+syntax:set("operator", grey3) -- Operators, light purple/gray
syntax:set("boolean", green) -- Booleans, bright green
syntax:set("table", purple) -- Tables, light purple
syntax:set("reference", pink) -- References, vibrant pink
@@ -69,7 +62,7 @@ syntax:set("tag", darkblue) -- Tags (e.g. HTML tags), cyan
syntax:set("heading", purple) -- Headings, light purple
syntax:set("link", pink) -- Links, vibrant pink
syntax:set("key", pink) -- Keys, vibrant pink
-syntax:set("quote", verylightgrey) -- Quotes, light purple/gray
+syntax:set("quote", grey3) -- Quotes, light purple/gray
syntax:set("bold", red) -- Bold text, cyan
syntax:set("italic", orange) -- Italic text, cyan
syntax:set("block", lightblue) -- Code blocks, cyan
@@ -77,7 +70,3 @@ syntax:set("image", lightblue) -- Images in markup languages, cyan
syntax:set("list", green) -- Lists, bright green
syntax:set("insertion", green) -- Insertions (e.g. diff highlight), bright green
syntax:set("deletion", red) -- Deletions (e.g. diff highlight), red
-
--- Import plugins (must be at the bottom of this file)
-load_plugin("pairs.lua")
-load_plugin("autoindent.lua")
diff --git a/src/themes/transparent.lua b/src/themes/transparent.lua
new file mode 100644
index 00000000..8a22e97f
--- /dev/null
+++ b/src/themes/transparent.lua
@@ -0,0 +1,8 @@
+
+-- Configure Colours --
+colors.editor_bg = 'transparent'
+colors.line_number_bg = 'transparent'
+
+colors.info_bg = 'transparent'
+colors.warning_bg = 'transparent'
+colors.error_bg = 'transparent'
diff --git a/config/tropical.lua b/src/themes/tropical.lua
similarity index 73%
rename from config/tropical.lua
rename to src/themes/tropical.lua
index 3e4eabae..fd604832 100644
--- a/config/tropical.lua
+++ b/src/themes/tropical.lua
@@ -1,16 +1,9 @@
--- Define user-defined commands
-commands = {
- ["reload"] = function(arguments)
- editor:reload_config()
- editor:display_info("Configuration file and plugins reloaded")
- end,
-}
-- Pallette --
black = '#232336'
-darkgrey = '#353552'
-lightgrey = '#484863'
-verylightgrey = '#A1A7C7'
+grey1 = '#353552'
+grey2 = '#484863'
+grey3 = '#A1A7C7'
white = '#cdd6f4'
brown = '#dd7878'
red = '#ed8796'
@@ -22,37 +15,35 @@ darkblue = '#8aadf4'
purple = '#c6a0f6'
pink = '#f5bde6'
--- PRIORITISE - ORANGE, RED, YELLOW, DARKBLUE, BROWN, GREEN, PINK
-
-- Configure Colours --
colors.editor_bg = black
colors.editor_fg = white
-colors.line_number_fg = lightgrey
+colors.line_number_fg = grey2
colors.line_number_bg = black
-colors.status_bg = darkgrey
+colors.status_bg = grey1
colors.status_fg = orange
colors.highlight = orange
-colors.tab_inactive_bg = darkgrey
+colors.tab_inactive_bg = grey1
colors.tab_inactive_fg = white
-colors.tab_active_bg = lightgrey
+colors.tab_active_bg = grey2
colors.tab_active_fg = orange
colors.info_bg = black
-colors.info_fg = lightblue
+colors.info_fg = darkblue
colors.warning_bg = black
colors.warning_fg = yellow
colors.error_bg = black
colors.error_fg = red
-colors.selection_bg = darkgrey
+colors.selection_bg = grey1
colors.selection_fg = lightblue
-- Configure Syntax Highlighting Colours --
syntax:set("string", lightblue) -- Strings, bright green
-syntax:set("comment", verylightgrey) -- Comments, light purple/gray
+syntax:set("comment", grey3) -- Comments, light purple/gray
syntax:set("digit", lightblue) -- Digits, cyan
syntax:set("keyword", orange) -- Keywords, vibrant pink
syntax:set("attribute", darkblue) -- Attributes, cyan
@@ -71,7 +62,7 @@ syntax:set("tag", orange) -- Tags (e.g. HTML tags), cyan
syntax:set("heading", red) -- Headings, light purple
syntax:set("link", darkblue) -- Links, vibrant pink
syntax:set("key", yellow) -- Keys, vibrant pink
-syntax:set("quote", verylightgrey) -- Quotes, light purple/gray
+syntax:set("quote", grey3) -- Quotes, light purple/gray
syntax:set("bold", red) -- Bold text, cyan
syntax:set("italic", orange) -- Italic text, cyan
syntax:set("block", red) -- Code blocks, cyan
@@ -79,7 +70,3 @@ syntax:set("image", red) -- Images in markup languages, cyan
syntax:set("list", red) -- Lists, bright green
syntax:set("insertion", green) -- Insertions (e.g. diff highlight), bright green
syntax:set("deletion", red) -- Deletions (e.g. diff highlight), red
-
--- Import plugins (must be at the bottom of this file)
-load_plugin("pairs.lua")
-load_plugin("autoindent.lua")
From 208d52201229bc4b6ab995af6eea33b09732364f Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Fri, 18 Oct 2024 23:27:33 +0100
Subject: [PATCH 04/27] Modernised missing plug-in message and added final
message to config assistant
---
src/config/assistant.rs | 17 +++++++++++++++++
src/plugin/run.lua | 3 +--
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/src/config/assistant.rs b/src/config/assistant.rs
index 173bb50e..7690038f 100644
--- a/src/config/assistant.rs
+++ b/src/config/assistant.rs
@@ -75,6 +75,21 @@ Typing Speed - Shows the rough speed that you're typing in the status line
Update Notification - Warns you if there is a new version of Ox - requires curl to be installed on unix based systems\n
";
+const FINAL_WORDS: &str = r"
+Configuration file was successfully written.
+
+Just a few things before you go:
+
+See the documentation here: https://github.com/curlpipe/ox/wiki
+Report any bugs or request new features here: https://github.com/curlpipe/ox/issues/new/choose
+
+Remember: You can press Ctrl + H when you are in the editor to reveal a help message to get started
+
+I hope you enjoy your Ox experience
+
+Ready? Press the enter key to start Ox
+";
+
#[derive(PartialEq)]
pub enum Theme {
Tropical,
@@ -280,6 +295,8 @@ impl Assistant {
println!("Below is your newly generated configuration file:\n\n");
println!("{result}");
}
+ println!("{FINAL_WORDS}");
+ let _ = gets!();
}
Ok(())
}
diff --git a/src/plugin/run.lua b/src/plugin/run.lua
index 2bb0cf2f..50c40841 100644
--- a/src/plugin/run.lua
+++ b/src/plugin/run.lua
@@ -51,8 +51,7 @@ remap_keys("before:ctrl_alt_space", "before:ctrl_alt_ ")
-- Show warning if any plugins weren't able to be loaded
if plugin_issues then
print("Various plug-ins failed to load")
- print("You may download these plug-ins from the ox git repository (in the plugins folder)")
- print("https://github.com/curlpipe/ox")
+ print("You may download these plug-ins by running the command `plugin install [plugin_name]`")
print("")
print("Alternatively, you may silence these warnings\nby removing the load_plugin() lines in your configuration file\nfor the missing plug-ins that are listed above")
end
From 0b03ebc76d5b30cac8932cb7a55372ea0b9faa2e Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sat, 19 Oct 2024 01:12:53 +0100
Subject: [PATCH 05/27] Added illustrations and clears the screen for different
sections
---
src/config/assistant.rs | 278 ++++++++++++++++++++++++++++------------
1 file changed, 193 insertions(+), 85 deletions(-)
diff --git a/src/config/assistant.rs b/src/config/assistant.rs
index 7690038f..52afadd6 100644
--- a/src/config/assistant.rs
+++ b/src/config/assistant.rs
@@ -1,13 +1,15 @@
use crate::cli::VERSION;
/// Code for the configuration set-up assistant
-use crate::config::{Colors, Indentation, SyntaxHighlighting};
+use crate::config::{Color, Colors, Indentation, SyntaxHighlighting};
use crate::error::Result;
+use crossterm::cursor::MoveTo;
+use crossterm::execute;
use crossterm::style::{SetBackgroundColor as Bg, SetForegroundColor as Fg};
+use crossterm::terminal::{Clear, ClearType};
use mlua::prelude::*;
use std::cell::RefCell;
-use std::io::Write;
+use std::io::{stdout, Write};
use std::rc::Rc;
-//use crate::config::Color;
//use std::collections::HashMap;
pub const TROPICAL: &str = include_str!("../themes/tropical.lua");
@@ -48,7 +50,7 @@ This way, you'll have a better user experience out of the box.
const INTRODUCTION: &str = r"
Welcome to the configuration assistant for the Ox Editor.
This is a tool that will help get Ox set up for you.
-It will take no more than 5 minutes and the config assistant will not show again after set-up.
+It will take no more than 3 minutes and the config assistant will not show again after set-up.
You can always re-access this tool using `ox --config-assist`
";
@@ -191,7 +193,7 @@ impl Default for Assistant {
impl Assistant {
/// Run the configuration assistant
pub fn run(because_no_config: bool) -> Result<()> {
- println!("{TITLE}");
+ Self::reset()?;
if because_no_config {
println!("{NO_CONFIG_MESSAGE}");
}
@@ -199,98 +201,33 @@ impl Assistant {
if Self::confirmation("Do you wish to set-up the editor?", true) {
let mut result = Self::default();
// Theme
- println!("Let's begin with what theme you'd like to use\n\n");
- // Prepare demonstration
- Self::demonstrate_themes()?;
- let choice = Self::options(
- "Please choose which theme you'd like",
- &["default", "tropical", "galaxy", "transparent"],
- "default",
- );
- result.theme = match choice.as_str() {
- "default" => Theme::Default,
- "tropical" => Theme::Tropical,
- "galaxy" => Theme::Galaxy,
- "transparent" => Theme::Transparent,
- _ => unreachable!(),
- };
+ Self::ask_theme(&mut result)?;
// Document
- println!("Great choice, now let's move onto indentation\n");
- result.indentation = Self::options(
- "Please choose how you'd like to represent indentation",
- &["spaces", "tabs"],
- "tabs",
- )
- .into();
- result.tab_width = if result.indentation == Indentation::Tabs {
- Self::integer("How wide should tabs be rendered as", 4)
- } else {
- Self::integer("How many spaces should make up 1 indent", 4)
- };
+ Self::ask_document(&mut result)?;
// Line Numbers
- println!("Great, now for deciding which parts of the editor should be visible\n");
- result.line_numbers =
- Self::confirmation("Would you like line numbers to be visible", true);
- if result.line_numbers {
- result.line_number_padding = (
- Self::integer(
- "How much space should there be on the left hand side of the line numbers",
- 1,
- ),
- Self::integer(
- "How much space should there be on the right hand side of the line numbers",
- 1,
- ),
- );
- }
+ Self::ask_line_numbers(&mut result)?;
// Tab line
- result.tab_line = Self::confirmation("Would you like the tab line to be visible", true);
- // Greeting message
- result.greeting_message = Self::confirmation(
- "Would you like the greeting message to be visible on start-up",
- true,
- );
+ Self::ask_tab_line(&mut result)?;
// Mouse and Cursor
- println!("Now for the mouse and cursor behaviour\n");
- result.mouse = Self::confirmation(
- "Would you like to use your mouse cursor in the editor",
- true,
- );
- result.scroll_sensitivity = Self::integer(
- "How sensitive should scrolling be, 1 = least sensitive, 5 = very sensitive",
- 2,
- );
- result.cursor_wrap = Self::confirmation(
- "Would you like the cursor to wrap around when at the edge of a line",
- true,
- );
+ Self::ask_mouse_cursor(&mut result)?;
// Icons
- println!("Ox has support for icons, which can enhance the UI, if you choose to enable them, ensure you install nerd fonts\n");
- result.icons =
- Self::confirmation("Would you like to enable icons, yes is recommended", false);
+ Self::ask_icons(&mut result)?;
// Plug-Ins
- Self::ask_plugins(&mut result);
+ Self::ask_plugins(&mut result)?;
// Create the configuration file (and print it)
+ Self::reset()?;
println!("\nSet-up is complete!");
if !because_no_config {
- println!("WARNING: config file already exists, it will be backed-up to ~/.oxrc-backup if you write");
+ let yellow = Fg(Color::Ansi(220).to_color()?);
+ let reset = Fg(Color::Transparent.to_color()?);
+ println!("{yellow}WARNING{reset}: config file already exists, it will be backed-up to ~/.oxrc-backup if you write");
}
let result = result.to_config();
if Self::confirmation(
"Would you like to write the configuration file?",
because_no_config,
) {
- let config_path = format!("{}/.oxrc", shellexpand::tilde("~"));
- let backup_path = format!("{}/.oxrc-backup", shellexpand::tilde("~"));
- if !because_no_config {
- let _ = std::fs::rename(config_path.clone(), backup_path);
- }
- let mut file = std::fs::OpenOptions::new()
- .write(true)
- .create(true)
- .truncate(true)
- .open(config_path)?;
- file.write_all(result.as_bytes())?;
+ Self::write_config(&result, because_no_config)?;
} else {
println!("Below is your newly generated configuration file:\n\n");
println!("{result}");
@@ -301,6 +238,27 @@ impl Assistant {
Ok(())
}
+ pub fn reset() -> Result<()> {
+ execute!(stdout(), Clear(ClearType::All), MoveTo(0, 0))?;
+ println!("{TITLE}");
+ Ok(())
+ }
+
+ pub fn write_config(result: &str, because_no_config: bool) -> Result<()> {
+ let config_path = format!("{}/.oxrc", shellexpand::tilde("~"));
+ let backup_path = format!("{}/.oxrc-backup", shellexpand::tilde("~"));
+ if !because_no_config {
+ let _ = std::fs::rename(config_path.clone(), backup_path);
+ }
+ let mut file = std::fs::OpenOptions::new()
+ .write(true)
+ .create(true)
+ .truncate(true)
+ .open(config_path)?;
+ file.write_all(result.as_bytes())?;
+ Ok(())
+ }
+
pub fn confirmation(msg: &str, default: bool) -> bool {
let mut response = "#####################".to_string();
while response != "y" && response != "n" && !response.is_empty() {
@@ -348,12 +306,161 @@ impl Assistant {
response.parse::().unwrap()
}
}
-
- pub fn ask_plugins(result: &mut Self) {
+
+ pub fn ask_theme(result: &mut Self) -> Result<()> {
+ Self::reset()?;
+ println!("Let's begin with what theme you'd like to use\n\n");
+ // Prepare demonstration
+ Self::demonstrate_themes()?;
+ let choice = Self::options(
+ "Please choose which theme you'd like",
+ &["default", "tropical", "galaxy", "transparent"],
+ "default",
+ );
+ result.theme = match choice.as_str() {
+ "default" => Theme::Default,
+ "tropical" => Theme::Tropical,
+ "galaxy" => Theme::Galaxy,
+ "transparent" => Theme::Transparent,
+ _ => unreachable!(),
+ };
+ Ok(())
+ }
+
+ pub fn ask_document(result: &mut Self) -> Result<()> {
+ let red = Fg(Color::Ansi(196).to_color()?);
+ let orange = Fg(Color::Ansi(202).to_color()?);
+ let yellow = Fg(Color::Ansi(220).to_color()?);
+ let green = Fg(Color::Ansi(34).to_color()?);
+ let blue = Fg(Color::Ansi(39).to_color()?);
+ let purple = Fg(Color::Ansi(141).to_color()?);
+ let pink = Fg(Color::Ansi(213).to_color()?);
+ let reset = Fg(Color::Transparent.to_color()?);
+ Self::reset()?;
+ println!("Great choice, now let's move onto indentation\n");
+ println!("{purple}_{blue}_{purple}_{blue}_{reset}spaces");
+ println!(" tabs\n{purple}‾‾‾‾{reset}");
+ result.indentation = Self::options(
+ "Please choose how you'd like to represent indentation",
+ &["spaces", "tabs"],
+ "tabs",
+ )
+ .into();
+ println!("{red}•{reset}1");
+ println!("{orange}••{reset}2");
+ println!("{yellow}•••{reset}3");
+ println!("{green}••••{reset}4");
+ println!("{blue}•••••{reset}5");
+ println!("{purple}••••••{reset}6");
+ println!("{pink}•••••••{reset}7");
+ println!("••••••••8\n");
+ result.tab_width = if result.indentation == Indentation::Tabs {
+ Self::integer("How wide should tabs be rendered as", 4)
+ } else {
+ Self::integer("How many spaces should make up 1 indent", 4)
+ };
+ Ok(())
+ }
+
+ pub fn ask_mouse_cursor(result: &mut Self) -> Result<()> {
+ let red = Fg(Color::Ansi(196).to_color()?);
+ let yellow = Fg(Color::Ansi(220).to_color()?);
+ let green = Fg(Color::Ansi(34).to_color()?);
+ let blue = Fg(Color::Ansi(39).to_color()?);
+ let purple = Fg(Color::Ansi(141).to_color()?);
+ let pink = Fg(Color::Ansi(213).to_color()?);
+ let reset = Fg(Color::Transparent.to_color()?);
+ Self::reset()?;
+ println!("Now for the mouse and cursor behaviour\n");
+ println!("{blue}🖰 {reset}Clicking to move cursor, {purple}◅ 🖰 ▻ {reset} Dragging to select text\n");
+ result.mouse = Self::confirmation(
+ "Would you like to use your mouse cursor in the editor",
+ true,
+ );
+ println!("{red}🖰 ⭥ {reset} {yellow}🖰 ⭥ {reset} {green}🖰 ⭥ {reset}\n");
+ result.scroll_sensitivity = Self::integer(
+ "How sensitive should scrolling be, 1 = least sensitive, 5 = very sensitive",
+ 2,
+ );
+ println!(" Cursor wraps{pink}|{reset}→ \n ↳ {pink}|{reset}Onto new line\n");
+ result.cursor_wrap = Self::confirmation(
+ "Would you like the cursor to wrap around when at the edge of a line",
+ true,
+ );
+ Ok(())
+ }
+
+ pub fn ask_tab_line(result: &mut Self) -> Result<()> {
+ let orange = Fg(Color::Ansi(202).to_color()?);
+ let yellow = Fg(Color::Ansi(220).to_color()?);
+ let green = Fg(Color::Ansi(34).to_color()?);
+ let purple = Fg(Color::Ansi(141).to_color()?);
+ let reset = Fg(Color::Transparent.to_color()?);
+ println!(
+ "| {purple}File 1{reset} | {green}File 2{reset} | {orange}File 3{reset} |\n"
+ );
+ result.tab_line = Self::confirmation("Would you like the tab line to be visible", true);
+ // Greeting message
+ println!(" {yellow}Welcome to Ox Editor!{reset} \n");
+ result.greeting_message = Self::confirmation(
+ "Would you like the greeting message to be visible on start-up",
+ true,
+ );
+ Ok(())
+ }
+
+ pub fn ask_line_numbers(result: &mut Self) -> Result<()> {
+ let red = Fg(Color::Ansi(196).to_color()?);
+ let orange = Fg(Color::Ansi(202).to_color()?);
+ let yellow = Fg(Color::Ansi(220).to_color()?);
+ let green = Fg(Color::Ansi(34).to_color()?);
+ let reset = Fg(Color::Transparent.to_color()?);
+ Self::reset()?;
+ println!("Great, now for deciding which parts of the editor should be visible\n");
+ println!("{green} 1 {reset}│");
+ println!("{yellow} 2 {reset}│");
+ println!("{red} 3 {reset}│\n");
+ result.line_numbers = Self::confirmation("Would you like line numbers to be visible", true);
+ if result.line_numbers {
+ println!("{red}•{reset}1 │");
+ println!("{orange}••{reset}2 │");
+ println!("{yellow}•••{reset}3 │\n");
+ let left_tab = Self::integer(
+ "How much space should there be on the left hand side of the line numbers",
+ 1,
+ );
+ println!(" 1{red}•{reset}│");
+ println!(" 2{orange}••{reset}│");
+ println!(" 3{yellow}•••{reset}│\n");
+ let right_tab = Self::integer(
+ "How much space should there be on the right hand side of the line numbers",
+ 1,
+ );
+ result.line_number_padding = (left_tab, right_tab);
+ }
+ Ok(())
+ }
+
+ pub fn ask_icons(result: &mut Self) -> Result<()> {
+ let yellow = Fg(Color::Ansi(220).to_color()?);
+ let blue = Fg(Color::Ansi(39).to_color()?);
+ let reset = Fg(Color::Transparent.to_color()?);
+ Self::reset()?;
+ println!("{blue}🖹 {yellow}🖉 {reset}");
+ println!("Ox has support for icons, which can enhance the UI, if you choose to enable them, ensure you install nerd fonts\n");
+ result.icons =
+ Self::confirmation("Would you like to enable icons, yes is recommended", false);
+ Ok(())
+ }
+
+ pub fn ask_plugins(result: &mut Self) -> Result<()> {
+ Self::reset()?;
+ let green = Fg(Color::Ansi(34).to_color()?);
+ let reset = Fg(Color::Transparent.to_color()?);
println!("{PLUGIN_LIST}");
let mut adding = String::new();
while adding != "exit" {
- println!("Enabled plug-ins: {:?}\n", result.plugins);
+ println!("{green}Enabled plug-ins:{reset} {:?}\n", result.plugins);
adding = Self::options(
"Enter the name of a plug-in you'd like to enable / disable",
&[
@@ -390,6 +497,7 @@ impl Assistant {
result.plugins.push(plugin);
}
}
+ Ok(())
}
pub fn demonstrate_themes() -> Result<()> {
From 9556ed18e34dfa9ddfb17d69aea0035e838f108c Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sat, 19 Oct 2024 11:12:23 +0100
Subject: [PATCH 06/27] Installed plug-ins for user after configuration set-up
---
src/config/assistant.rs | 58 +++++++++++++++++++++++++++--------------
1 file changed, 39 insertions(+), 19 deletions(-)
diff --git a/src/config/assistant.rs b/src/config/assistant.rs
index 52afadd6..a4863742 100644
--- a/src/config/assistant.rs
+++ b/src/config/assistant.rs
@@ -2,6 +2,7 @@ use crate::cli::VERSION;
/// Code for the configuration set-up assistant
use crate::config::{Color, Colors, Indentation, SyntaxHighlighting};
use crate::error::Result;
+use crate::{PLUGIN_BOOTSTRAP, PLUGIN_MANAGER, PLUGIN_NETWORKING};
use crossterm::cursor::MoveTo;
use crossterm::execute;
use crossterm::style::{SetBackgroundColor as Bg, SetForegroundColor as Fg};
@@ -92,6 +93,13 @@ I hope you enjoy your Ox experience
Ready? Press the enter key to start Ox
";
+const PLUGIN_INSTALL: &str = r#"
+if not plugin_manager:plugin_downloaded('{name}') then
+ print("Installing " .. '{name}')
+ plugin_manager:download_plugin('{name}')
+end
+"#;
+
#[derive(PartialEq)]
pub enum Theme {
Tropical,
@@ -129,21 +137,23 @@ pub enum Plugin {
impl Plugin {
pub fn to_config(&self) -> String {
- format!(
- "load_plugin(\"{}\")\n",
- match self {
- Self::AutoIndent => "autoindent.lua",
- Self::Pairs => "pairs.lua",
- Self::DiscordRPC => "discord_rpc.lua",
- Self::Emmet => "emmet.lua",
- Self::Git => "git.lua",
- Self::LiveHTML => "live_html.lua",
- Self::Pomodoro => "pomodoro.lua",
- Self::Todo => "todo.lua",
- Self::TypingSpeed => "typing_speed.lua",
- Self::UpdateNotification => "update_notification.lua",
- }
- )
+ let plugin_name = self.name();
+ format!("load_plugin(\"{plugin_name}.lua\")\n")
+ }
+
+ pub fn name(&self) -> &str {
+ match self {
+ Self::AutoIndent => "autoindent",
+ Self::Pairs => "pairs",
+ Self::DiscordRPC => "discord_rpc",
+ Self::Emmet => "emmet",
+ Self::Git => "git",
+ Self::LiveHTML => "live_html",
+ Self::Pomodoro => "pomodoro",
+ Self::Todo => "todo",
+ Self::TypingSpeed => "typing_speed",
+ Self::UpdateNotification => "update_notification",
+ }
}
}
@@ -222,15 +232,15 @@ impl Assistant {
let reset = Fg(Color::Transparent.to_color()?);
println!("{yellow}WARNING{reset}: config file already exists, it will be backed-up to ~/.oxrc-backup if you write");
}
- let result = result.to_config();
+ let contents = result.to_config();
if Self::confirmation(
"Would you like to write the configuration file?",
because_no_config,
) {
- Self::write_config(&result, because_no_config)?;
+ Self::write_config(&result.plugins, &contents, because_no_config)?;
} else {
println!("Below is your newly generated configuration file:\n\n");
- println!("{result}");
+ println!("{contents}");
}
println!("{FINAL_WORDS}");
let _ = gets!();
@@ -244,7 +254,7 @@ impl Assistant {
Ok(())
}
- pub fn write_config(result: &str, because_no_config: bool) -> Result<()> {
+ pub fn write_config(plugins: &Vec, result: &str, because_no_config: bool) -> Result<()> {
let config_path = format!("{}/.oxrc", shellexpand::tilde("~"));
let backup_path = format!("{}/.oxrc-backup", shellexpand::tilde("~"));
if !because_no_config {
@@ -256,6 +266,16 @@ impl Assistant {
.truncate(true)
.open(config_path)?;
file.write_all(result.as_bytes())?;
+ // Install plug-ins
+ let lua = Lua::new();
+ lua.load("commands = {}").exec()?;
+ lua.load(PLUGIN_BOOTSTRAP).exec()?;
+ lua.load(PLUGIN_NETWORKING).exec()?;
+ lua.load(PLUGIN_MANAGER).exec()?;
+ for plugin in plugins {
+ let plugin_name = plugin.name();
+ lua.load(PLUGIN_INSTALL.replace("{name}", plugin_name)).exec()?;
+ }
Ok(())
}
From 218e3fad0dcfc65d206ef77ede86bdbf618bc5c0 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sat, 19 Oct 2024 11:12:51 +0100
Subject: [PATCH 07/27] rustfmt
---
src/config/assistant.rs | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/src/config/assistant.rs b/src/config/assistant.rs
index a4863742..4dec4b5f 100644
--- a/src/config/assistant.rs
+++ b/src/config/assistant.rs
@@ -140,7 +140,7 @@ impl Plugin {
let plugin_name = self.name();
format!("load_plugin(\"{plugin_name}.lua\")\n")
}
-
+
pub fn name(&self) -> &str {
match self {
Self::AutoIndent => "autoindent",
@@ -254,7 +254,11 @@ impl Assistant {
Ok(())
}
- pub fn write_config(plugins: &Vec, result: &str, because_no_config: bool) -> Result<()> {
+ pub fn write_config(
+ plugins: &Vec,
+ result: &str,
+ because_no_config: bool,
+ ) -> Result<()> {
let config_path = format!("{}/.oxrc", shellexpand::tilde("~"));
let backup_path = format!("{}/.oxrc-backup", shellexpand::tilde("~"));
if !because_no_config {
@@ -274,7 +278,8 @@ impl Assistant {
lua.load(PLUGIN_MANAGER).exec()?;
for plugin in plugins {
let plugin_name = plugin.name();
- lua.load(PLUGIN_INSTALL.replace("{name}", plugin_name)).exec()?;
+ lua.load(PLUGIN_INSTALL.replace("{name}", plugin_name))
+ .exec()?;
}
Ok(())
}
From bd4444fb38fb5a97ba871f22f09ecfc655e39bc1 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sat, 19 Oct 2024 17:06:39 +0100
Subject: [PATCH 08/27] Fixed minor issues with Rust syntax highlighting
---
Cargo.lock | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index c4e11b78..8f8d42cc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -56,9 +56,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
-version = "1.1.30"
+version = "1.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945"
+checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f"
dependencies = [
"shlex",
]
@@ -183,9 +183,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.159"
+version = "0.2.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
+checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
[[package]]
name = "libredox"
@@ -359,9 +359,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.87"
+version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a"
+checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9"
dependencies = [
"unicode-ident",
]
@@ -591,9 +591,9 @@ dependencies = [
[[package]]
name = "synoptic"
-version = "2.0.8"
+version = "2.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1397c98697342b5b76b1dce4ecf2a912dc6407257b7db8c3006ab7d9b69b5b70"
+checksum = "58e69f54fedd3b7dc77c792a22844c7917102ecd2bb6f6a7f3347863e0b23540"
dependencies = [
"if_chain",
"regex",
From a7a8f54e9e1e2e18da2a4e87b00aceb5d7edd02c Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sat, 19 Oct 2024 17:15:59 +0100
Subject: [PATCH 09/27] Fixed issue with file path prompt not having a
background
---
src/editor/interface.rs | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/editor/interface.rs b/src/editor/interface.rs
index 50c2019c..98ab09d0 100644
--- a/src/editor/interface.rs
+++ b/src/editor/interface.rs
@@ -290,6 +290,7 @@ impl Editor {
}
/// Prompt for selecting a file
+ #[allow(clippy::similar_names)]
pub fn path_prompt(&mut self) -> Result {
let mut input = get_cwd().map(|s| s + "/").unwrap_or_default();
let mut offset = 0;
@@ -328,12 +329,18 @@ impl Editor {
.skip(input.chars().count())
.collect::();
let editor_fg = Fg(self.config.colors.borrow().editor_fg.to_color()?);
+ let editor_bg = Bg(self.config.colors.borrow().editor_bg.to_color()?);
+ let tab_width = self.config.document.borrow().tab_width;
+ let total_width = width(&input, tab_width) + width(&suggestion_text, tab_width);
+ let padding = " ".repeat(size()?.w.saturating_sub(total_width));
display!(
self,
+ editor_bg,
"Path: ",
input.clone(),
Fg(Color::DarkGrey),
suggestion_text,
+ padding,
editor_fg
);
let tab_width = self.config.document.borrow_mut().tab_width;
From 60f8e3906acbea1c50b38043284ce87f85d78813 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sat, 19 Oct 2024 17:25:08 +0100
Subject: [PATCH 10/27] Fixed particular instances of being able to edit a read
only file
---
src/editor/editing.rs | 43 ++++++++++++++++++++++++++++++-------------
1 file changed, 30 insertions(+), 13 deletions(-)
diff --git a/src/editor/editing.rs b/src/editor/editing.rs
index f86827fe..fa3ef3b8 100644
--- a/src/editor/editing.rs
+++ b/src/editor/editing.rs
@@ -18,7 +18,7 @@ impl Editor {
/// Insert a character into the document, creating a new row if editing
/// on the last line of the document
pub fn character(&mut self, ch: char) -> Result<()> {
- if !self.doc().is_selection_empty() {
+ if !self.doc().is_selection_empty() && !self.doc().info.read_only {
self.doc_mut().remove_selection();
self.reload_highlight();
}
@@ -30,7 +30,9 @@ impl Editor {
let loc = self.doc().char_loc();
self.exe(Event::Insert(loc, ch.to_string()))?;
let file = &mut self.files[self.ptr];
- file.highlighter.edit(loc.y, &file.doc.lines[loc.y]);
+ if !file.doc.info.read_only {
+ file.highlighter.edit(loc.y, &file.doc.lines[loc.y]);
+ }
}
Ok(())
}
@@ -46,17 +48,19 @@ impl Editor {
let loc = self.doc().char_loc();
self.exe(Event::SplitDown(loc))?;
let file = &mut self.files[self.ptr];
- let line = &file.doc.lines[loc.y + 1];
- file.highlighter.insert_line(loc.y + 1, line);
- let line = &file.doc.lines[loc.y];
- file.highlighter.edit(loc.y, line);
+ if !file.doc.info.read_only {
+ let line = &file.doc.lines[loc.y + 1];
+ file.highlighter.insert_line(loc.y + 1, line);
+ let line = &file.doc.lines[loc.y];
+ file.highlighter.edit(loc.y, line);
+ }
}
Ok(())
}
/// Handle the backspace key
pub fn backspace(&mut self) -> Result<()> {
- if !self.doc().is_selection_empty() {
+ if !self.doc().is_selection_empty() && !self.doc().info.read_only {
// Removing a selection is significant and worth an undo commit
self.doc_mut().commit();
self.doc_mut().undo_mgmt.set_dirty();
@@ -71,14 +75,19 @@ impl Editor {
// Backspace was pressed on the start of the line, move line to the top
self.new_row()?;
let mut loc = self.doc().char_loc();
- self.highlighter().remove_line(loc.y);
+ let file = &self.files[self.ptr];
+ if !file.doc.info.read_only {
+ self.highlighter().remove_line(loc.y);
+ }
loc.y = loc.y.saturating_sub(1);
let file = &mut self.files[self.ptr];
loc.x = file.doc.line(loc.y).unwrap().chars().count();
self.exe(Event::SpliceUp(loc))?;
let file = &mut self.files[self.ptr];
let line = &file.doc.lines[loc.y];
- file.highlighter.edit(loc.y, line);
+ if !file.doc.info.read_only {
+ file.highlighter.edit(loc.y, line);
+ }
} else if !(c == 0 && on_first_line) {
// Backspace was pressed in the middle of the line, delete the character
c = c.saturating_sub(1);
@@ -90,7 +99,9 @@ impl Editor {
};
self.exe(Event::Delete(loc, ch.to_string()))?;
let file = &mut self.files[self.ptr];
- file.highlighter.edit(loc.y, &file.doc.lines[loc.y]);
+ if !file.doc.info.read_only {
+ file.highlighter.edit(loc.y, &file.doc.lines[loc.y]);
+ }
}
}
}
@@ -108,7 +119,9 @@ impl Editor {
};
self.exe(Event::Delete(loc, ch.to_string()))?;
let file = &mut self.files[self.ptr];
- file.highlighter.edit(loc.y, &file.doc.lines[loc.y]);
+ if !file.doc.info.read_only {
+ file.highlighter.edit(loc.y, &file.doc.lines[loc.y]);
+ }
}
}
Ok(())
@@ -118,7 +131,9 @@ impl Editor {
fn new_row(&mut self) -> Result<()> {
if self.doc().loc().y == self.doc().len_lines() {
self.exe(Event::InsertLine(self.doc().loc().y, String::new()))?;
- self.highlighter().append(&String::new());
+ if !self.doc().info.read_only {
+ self.highlighter().append(&String::new());
+ }
}
Ok(())
}
@@ -130,7 +145,9 @@ impl Editor {
let y = self.doc().loc().y;
let line = self.doc().line(y).unwrap();
self.exe(Event::DeleteLine(y, line))?;
- self.highlighter().remove_line(y);
+ if !self.doc().info.read_only {
+ self.highlighter().remove_line(y);
+ }
}
Ok(())
}
From e93ed72e2f825830d1ac8457351a27dbde7bdd7b Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sat, 19 Oct 2024 22:50:28 +0100
Subject: [PATCH 11/27] Changed rendering code to prevent artefacts on long
lines
---
Cargo.lock | 10 +++++-----
src/editor/interface.rs | 24 ++++++++++++------------
2 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 8f8d42cc..099fcd30 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -580,9 +580,9 @@ checksum = "cc0db74f9ee706e039d031a560bd7d110c7022f016051b3d33eeff9583e3e67a"
[[package]]
name = "syn"
-version = "2.0.79"
+version = "2.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
+checksum = "e6e185e337f816bc8da115b8afcb3324006ccc82eeaddf35113888d3bd8e44ac"
dependencies = [
"proc-macro2",
"quote",
@@ -591,13 +591,13 @@ dependencies = [
[[package]]
name = "synoptic"
-version = "2.0.9"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58e69f54fedd3b7dc77c792a22844c7917102ecd2bb6f6a7f3347863e0b23540"
+checksum = "97419cc9b1e79552ca0622b66093fc5217d9b0048415f2c8680a52be2fcd41f7"
dependencies = [
"if_chain",
"regex",
- "unicode-width 0.1.14",
+ "unicode-width 0.2.0",
]
[[package]]
diff --git a/src/editor/interface.rs b/src/editor/interface.rs
index 98ab09d0..21401121 100644
--- a/src/editor/interface.rs
+++ b/src/editor/interface.rs
@@ -77,7 +77,15 @@ impl Editor {
.collect::>();
let start = u16::try_from(h / 4).unwrap_or(u16::MAX);
let end = start + u16::try_from(message.len()).unwrap_or(u16::MAX);
+ // Render each line of the document
for y in 0..u16::try_from(h).unwrap_or(0) {
+ // Work out how long the line should be (accounting for help message if necessary)
+ let required_width = if self.config.help_message.borrow().enabled && (start..=end).contains(&y) {
+ w.saturating_sub(self.dent()).saturating_sub(max_width)
+ } else {
+ w.saturating_sub(self.dent())
+ };
+ // Go to the right location
self.terminal.goto(0, y as usize + self.push_down)?;
// Start colours
let editor_bg = Bg(self.config.colors.borrow().editor_bg.to_color()?);
@@ -106,10 +114,9 @@ impl Editor {
}
// Render line if it exists
let idx = y as usize + self.doc().offset.y;
- let pad_amount;
if let Some(line) = self.doc().line(idx) {
let tokens = self.highlighter().line(idx, &line);
- let tokens = trim(&tokens, self.doc().offset.x);
+ let tokens = trim(&tokens, self.doc().offset.x, required_width, tab_width);
let mut x_pos = self.doc().offset.x;
for token in tokens {
// Find out the text (and colour of that text)
@@ -131,7 +138,7 @@ impl Editor {
// Highlighted text
TokOpt::None(text) => (text, editor_fg),
};
- // Do the rendering
+ // Do the rendering (including selection where applicable)
for c in text.chars() {
let at_x = self.doc().character_idx(&Loc { y: idx, x: x_pos });
let is_selected = self.doc().is_loc_selected(Loc { y: idx, x: at_x });
@@ -144,22 +151,15 @@ impl Editor {
x_pos += 1;
}
}
- // Pad out the line (to remove any junk left over from previous render)
display!(self, editor_fg, editor_bg);
- let tab_width = self.config.document.borrow().tab_width;
- let line_width = width(&line, tab_width);
- pad_amount = w.saturating_sub(self.dent()).saturating_sub(line_width) + 1;
} else {
- // Render empty line
- pad_amount = w.saturating_sub(self.dent()) + 1;
+ // Empty line, just pad out with spaces to prevent artefacts
+ display!(self, " ".repeat(required_width));
}
// Render help message if applicable (otherwise, just output padding to clear buffer)
if self.config.help_message.borrow().enabled && (start..=end).contains(&y) {
let idx = y.saturating_sub(start);
- display!(self, " ".repeat(pad_amount.saturating_sub(max_width)));
display!(self, message.get(idx as usize).unwrap_or(&String::new()));
- } else {
- display!(self, " ".repeat(pad_amount));
}
}
Ok(())
From 0e866048d04a812312912e172276bb455dac68bb Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sat, 19 Oct 2024 23:14:26 +0100
Subject: [PATCH 12/27] Fixed line loading bug and commit to event stack when
pasting
---
src/editor/interface.rs | 11 ++++++-----
src/editor/mod.rs | 4 +++-
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/editor/interface.rs b/src/editor/interface.rs
index 21401121..b881c19c 100644
--- a/src/editor/interface.rs
+++ b/src/editor/interface.rs
@@ -80,11 +80,12 @@ impl Editor {
// Render each line of the document
for y in 0..u16::try_from(h).unwrap_or(0) {
// Work out how long the line should be (accounting for help message if necessary)
- let required_width = if self.config.help_message.borrow().enabled && (start..=end).contains(&y) {
- w.saturating_sub(self.dent()).saturating_sub(max_width)
- } else {
- w.saturating_sub(self.dent())
- };
+ let required_width =
+ if self.config.help_message.borrow().enabled && (start..=end).contains(&y) {
+ w.saturating_sub(self.dent()).saturating_sub(max_width)
+ } else {
+ w.saturating_sub(self.dent())
+ };
// Go to the right location
self.terminal.goto(0, y as usize + self.push_down)?;
// Start colours
diff --git a/src/editor/mod.rs b/src/editor/mod.rs
index f1f778c8..93da0305 100644
--- a/src/editor/mod.rs
+++ b/src/editor/mod.rs
@@ -378,7 +378,7 @@ impl Editor {
let max = self.dent();
self.doc_mut().size.w = w.saturating_sub(u16::try_from(max).unwrap_or(u16::MAX)) as usize;
self.doc_mut().size.h = h.saturating_sub(3) as usize;
- let max = self.doc().offset.x + self.doc().size.h;
+ let max = self.doc().offset.y + self.doc().size.h;
self.doc_mut().load_to(max + 1);
}
@@ -387,6 +387,8 @@ impl Editor {
for ch in text.chars() {
self.character(ch)?;
}
+ // Paste warrants a commit here really
+ self.doc_mut().commit();
Ok(())
}
From 335f96913fae0fc95a2b80ca536e1b640d2c0375 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sat, 19 Oct 2024 23:31:03 +0100
Subject: [PATCH 13/27] Tabs now open in a much better order
---
src/editor/mod.rs | 22 ++++++++++++++++------
src/main.rs | 4 ++++
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/src/editor/mod.rs b/src/editor/mod.rs
index 93da0305..c9c1f2e6 100644
--- a/src/editor/mod.rs
+++ b/src/editor/mod.rs
@@ -101,18 +101,23 @@ impl Editor {
// Mark as not saved on disk
doc.info.modified = true;
// Add document to documents
- self.files.push(FileContainer {
+ let file = FileContainer {
highlighter,
file_type: Some(FileType::default()),
doc,
- });
+ };
+ if self.ptr + 1 >= self.files.len() {
+ self.files.push(file);
+ } else {
+ self.files.insert(self.ptr + 1, file);
+ }
Ok(())
}
/// Create a new document and move to it
pub fn new_document(&mut self) -> Result<()> {
self.blank()?;
- self.ptr = self.files.len().saturating_sub(1);
+ self.next();
Ok(())
}
@@ -144,11 +149,16 @@ impl Editor {
});
highlighter.run(&doc.lines);
// Add in the file
- self.files.push(FileContainer {
+ let file = FileContainer {
doc,
highlighter,
file_type,
- });
+ };
+ if self.ptr + 1 >= self.files.len() {
+ self.files.push(file);
+ } else {
+ self.files.insert(self.ptr + 1, file);
+ }
Ok(())
}
@@ -156,7 +166,7 @@ impl Editor {
pub fn open_document(&mut self) -> Result<()> {
let path = self.path_prompt()?;
self.open(&path)?;
- self.ptr = self.files.len().saturating_sub(1);
+ self.next();
self.update_cwd();
Ok(())
}
diff --git a/src/main.rs b/src/main.rs
index cd93af7e..57bdea63 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -111,7 +111,11 @@ fn run(cli: &CommandLineInterface) -> Result<()> {
file.highlighter = highlighter;
file.file_type = Some(file_type);
}
+ // Move the pointer to the file we just created
+ editor.borrow_mut().next();
}
+ // Reset the pointer back to the first document
+ editor.borrow_mut().ptr = 0;
// Handle stdin if applicable
if cli.flags.stdin {
From 0f991019a9aa2c3572b236d6d121958db096f575 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sun, 20 Oct 2024 11:02:21 +0100
Subject: [PATCH 14/27] Improved word traversal
---
kaolinite/src/document.rs | 12 ++++++++----
src/config/assistant.rs | 2 +-
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/kaolinite/src/document.rs b/kaolinite/src/document.rs
index f64d00a4..48d7fc8a 100644
--- a/kaolinite/src/document.rs
+++ b/kaolinite/src/document.rs
@@ -665,11 +665,12 @@ impl Document {
/// Moves to the previous word in the document
pub fn move_prev_word(&mut self) -> Status {
let Loc { x, y } = self.char_loc();
+ // Handle case where we're at the beginning of the line
if x == 0 && y != 0 {
return Status::StartOfLine;
}
- let re = format!("(\t| {{{}}}|^|\\W|$| )", self.tab_width);
- let mut searcher = Searcher::new(&re);
+ // Find where all the words are
+ let mut searcher = Searcher::new(r"(^|\s{2,}|[A-Za-z0-9_]+|\.)");
let line = self
.line(y)
.unwrap_or_default()
@@ -677,6 +678,8 @@ impl Document {
.take(x)
.collect::();
let mut matches = searcher.rfinds(&line);
+ matches.iter_mut().for_each(|m| m.loc.x += m.text.chars().count());
+ // Find the most appropriate one to move to given the cursor position
if let Some(mtch) = matches.first() {
if mtch.loc.x == x {
matches.remove(0);
@@ -694,11 +697,12 @@ impl Document {
pub fn move_next_word(&mut self) -> Status {
let Loc { x, y } = self.char_loc();
let line = self.line(y).unwrap_or_default();
+ // Handle case where we're at the end of the line
if x == line.chars().count() && y != self.len_lines() {
return Status::EndOfLine;
}
- let re = format!("(\t| {{{}}}|\\W|$|^ +| )", self.tab_width);
- if let Some(mut mtch) = self.next_match(&re, 0) {
+ // Find and move to the next word
+ if let Some(mut mtch) = self.next_match(r"(\s{2,}|[A-Za-z0-9_]+|$|\.)", 0) {
mtch.loc.x += mtch.text.chars().count();
self.move_to(&mtch.loc);
}
diff --git a/src/config/assistant.rs b/src/config/assistant.rs
index 4dec4b5f..0c64b2bd 100644
--- a/src/config/assistant.rs
+++ b/src/config/assistant.rs
@@ -1,5 +1,5 @@
-use crate::cli::VERSION;
/// Code for the configuration set-up assistant
+use crate::cli::VERSION;
use crate::config::{Color, Colors, Indentation, SyntaxHighlighting};
use crate::error::Result;
use crate::{PLUGIN_BOOTSTRAP, PLUGIN_MANAGER, PLUGIN_NETWORKING};
From 6aec15d8fffb4435684bafd51ebdecebdcda378c Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sun, 20 Oct 2024 11:13:46 +0100
Subject: [PATCH 15/27] Shift tab to dedent lines
---
kaolinite/src/document.rs | 4 +++-
plugins/autoindent.lua | 8 +++++++-
src/plugin/run.lua | 2 ++
3 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/kaolinite/src/document.rs b/kaolinite/src/document.rs
index 48d7fc8a..757851a5 100644
--- a/kaolinite/src/document.rs
+++ b/kaolinite/src/document.rs
@@ -678,7 +678,9 @@ impl Document {
.take(x)
.collect::();
let mut matches = searcher.rfinds(&line);
- matches.iter_mut().for_each(|m| m.loc.x += m.text.chars().count());
+ matches
+ .iter_mut()
+ .for_each(|m| m.loc.x += m.text.chars().count());
// Find the most appropriate one to move to given the cursor position
if let Some(mtch) = matches.first() {
if mtch.loc.x == x {
diff --git a/plugins/autoindent.lua b/plugins/autoindent.lua
index 9790d076..ba61ae9a 100644
--- a/plugins/autoindent.lua
+++ b/plugins/autoindent.lua
@@ -1,5 +1,5 @@
--[[
-Auto Indent v0.9
+Auto Indent v0.10
Helps you when programming by guessing where indentation should go
and then automatically applying these guesses as you program
@@ -191,3 +191,9 @@ for i = 32, 126 do
end
end
end
+
+-- Shortcut to dedent a line
+event_mapping["shift_tab"] = function()
+ local level = autoindent:get_indent(editor.cursor.y)
+ autoindent:set_indent(editor.cursor.y, level - 1)
+end
diff --git a/src/plugin/run.lua b/src/plugin/run.lua
index 50c40841..1955bfdc 100644
--- a/src/plugin/run.lua
+++ b/src/plugin/run.lua
@@ -43,10 +43,12 @@ remap_keys("space", " ")
remap_keys("ctrl_space", "ctrl_ ")
remap_keys("alt_space", "alt_ ")
remap_keys("ctrl_alt_space", "ctrl_alt_ ")
+remap_keys("shift_tab", "shift_backtab")
remap_keys("before:space", "before: ")
remap_keys("before:ctrl_space", "before:ctrl_ ")
remap_keys("before:alt_space", "before:alt_ ")
remap_keys("before:ctrl_alt_space", "before:ctrl_alt_ ")
+remap_keys("before:shift_tab", "before:shift_backtab")
-- Show warning if any plugins weren't able to be loaded
if plugin_issues then
From bfd883ed298c50372444e82be33fb19643cb7248 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sun, 20 Oct 2024 11:21:20 +0100
Subject: [PATCH 16/27] Fixed cursor position when moving lines up and down
---
config/.oxrc | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/config/.oxrc b/config/.oxrc
index 015d7e11..82ea911d 100644
--- a/config/.oxrc
+++ b/config/.oxrc
@@ -117,25 +117,27 @@ event_mapping = {
end,
["alt_up"] = function()
-- current line information
- line = editor:get_line()
- y = editor.cursor.y
+ local line = editor:get_line()
+ local cursor = editor.cursor
-- insert a new line
- editor:insert_line_at(line, y - 1)
+ editor:insert_line_at(line, cursor.y - 1)
-- delete old copy and reposition cursor
- editor:remove_line_at(y + 1)
- editor:move_up()
+ editor:remove_line_at(cursor.y + 1)
+ -- restore cursor position
+ editor:move_to(cursor.x, cursor.y - 1)
-- correct indentation level
autoindent:fix_indent()
end,
["alt_down"] = function()
-- current line information
- line = editor:get_line()
- y = editor.cursor.y
+ local line = editor:get_line()
+ local cursor = editor.cursor
-- insert a new line
- editor:insert_line_at(line, y + 2)
+ editor:insert_line_at(line, cursor.y + 2)
-- delete old copy and reposition cursor
- editor:remove_line_at(y)
- editor:move_down()
+ editor:remove_line_at(cursor.y)
+ -- restore cursor position
+ editor:move_to(cursor.x, cursor.y + 1)
-- correct indentation level
autoindent:fix_indent()
end,
From 47ad3db33cb82ebc2de4e9169fec392eb37480ba Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sun, 20 Oct 2024 11:47:08 +0100
Subject: [PATCH 17/27] updated tests
---
kaolinite/tests/test.rs | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/kaolinite/tests/test.rs b/kaolinite/tests/test.rs
index 970870d1..230db8e5 100644
--- a/kaolinite/tests/test.rs
+++ b/kaolinite/tests/test.rs
@@ -545,27 +545,33 @@ fn document_moving() {
doc.exe(Event::InsertLine(10, st!("these are words this.is.code()")));
doc.move_to(&Loc { x: 0, y: 10 });
doc.move_next_word();
- assert_eq!(doc.loc(), Loc { x: 6, y: 10 });
+ assert_eq!(doc.loc(), Loc { x: 5, y: 10 });
doc.move_next_word();
- assert_eq!(doc.loc(), Loc { x: 10, y: 10 });
+ assert_eq!(doc.loc(), Loc { x: 9, y: 10 });
doc.move_next_word();
- assert_eq!(doc.loc(), Loc { x: 16, y: 10 });
+ assert_eq!(doc.loc(), Loc { x: 15, y: 10 });
+ doc.move_next_word();
+ assert_eq!(doc.loc(), Loc { x: 20, y: 10 });
doc.move_next_word();
assert_eq!(doc.loc(), Loc { x: 21, y: 10 });
doc.move_next_word();
+ assert_eq!(doc.loc(), Loc { x: 23, y: 10 });
+ doc.move_next_word();
assert_eq!(doc.loc(), Loc { x: 24, y: 10 });
doc.move_next_word();
- assert_eq!(doc.loc(), Loc { x: 29, y: 10 });
+ assert_eq!(doc.loc(), Loc { x: 28, y: 10 });
doc.move_next_word();
assert_eq!(doc.loc(), Loc { x: 30, y: 10 });
assert_eq!(doc.move_next_word(), Status::EndOfLine);
doc.move_prev_word();
- assert_eq!(doc.loc(), Loc { x: 29, y: 10 });
- doc.move_prev_word();
assert_eq!(doc.loc(), Loc { x: 28, y: 10 });
doc.move_prev_word();
+ assert_eq!(doc.loc(), Loc { x: 24, y: 10 });
+ doc.move_prev_word();
assert_eq!(doc.loc(), Loc { x: 23, y: 10 });
doc.move_prev_word();
+ assert_eq!(doc.loc(), Loc { x: 21, y: 10 });
+ doc.move_prev_word();
assert_eq!(doc.loc(), Loc { x: 20, y: 10 });
doc.move_prev_word();
assert_eq!(doc.loc(), Loc { x: 15, y: 10 });
From fcf69800f40b0896d35f837558f5edcfe1c8c08a Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sun, 20 Oct 2024 13:57:01 +0100
Subject: [PATCH 18/27] Complete reimplementation of word deletion and moving
---
config/.oxrc | 19 +---
kaolinite/src/document.rs | 190 ++++++++++++++++++++++++++++++++-----
kaolinite/src/searching.rs | 2 +-
src/config/editor.rs | 4 +
4 files changed, 172 insertions(+), 43 deletions(-)
diff --git a/config/.oxrc b/config/.oxrc
index 82ea911d..4cc188d8 100644
--- a/config/.oxrc
+++ b/config/.oxrc
@@ -142,24 +142,7 @@ event_mapping = {
autoindent:fix_indent()
end,
["ctrl_w"] = function()
- y = editor.cursor.y
- x = editor.cursor.x
- if editor:get_character() == " " then
- start = 0
- else
- start = 1
- end
- editor:move_previous_word()
- new_x = editor.cursor.x
- diff = x - new_x
- if editor.cursor.y == y then
- -- Cursor on the same line
- for i = start, diff do
- editor:remove_at(new_x, y)
- end
- else
- -- Cursor has passed up onto the previous line
- end
+ editor:remove_word()
end,
}
diff --git a/kaolinite/src/document.rs b/kaolinite/src/document.rs
index 757851a5..3a32b27f 100644
--- a/kaolinite/src/document.rs
+++ b/kaolinite/src/document.rs
@@ -662,6 +662,38 @@ impl Document {
self.cancel_selection();
}
+ /// Find the word boundaries
+ pub fn word_boundaries(&mut self, line: &str) -> Vec<(usize, usize)> {
+ let re = r"(\s{2,}|[A-Za-z0-9_]+|\.)";
+ let mut searcher = Searcher::new(re);
+ let starts: Vec = searcher.lfinds(line);
+ let mut ends: Vec = starts.clone();
+ ends.iter_mut()
+ .for_each(|m| m.loc.x += m.text.chars().count());
+ let starts: Vec = starts.iter().map(|m| m.loc.x).collect();
+ let ends: Vec = ends.iter().map(|m| m.loc.x).collect();
+ starts.into_iter().zip(ends).collect()
+ }
+
+ /// Find the current state of the cursor in relation to words
+ pub fn cursor_word_state(&mut self, words: &[(usize, usize)], x: usize) -> WordState {
+ let in_word = words
+ .iter()
+ .position(|(start, end)| *start <= x && x <= *end);
+ if let Some(idx) = in_word {
+ let (word_start, word_end) = words[idx];
+ if x == word_end {
+ WordState::AtEnd(idx)
+ } else if x == word_start {
+ WordState::AtStart(idx)
+ } else {
+ WordState::InCenter(idx)
+ }
+ } else {
+ WordState::Out
+ }
+ }
+
/// Moves to the previous word in the document
pub fn move_prev_word(&mut self) -> Status {
let Loc { x, y } = self.char_loc();
@@ -670,27 +702,49 @@ impl Document {
return Status::StartOfLine;
}
// Find where all the words are
- let mut searcher = Searcher::new(r"(^|\s{2,}|[A-Za-z0-9_]+|\.)");
- let line = self
- .line(y)
- .unwrap_or_default()
- .chars()
- .take(x)
- .collect::();
- let mut matches = searcher.rfinds(&line);
- matches
- .iter_mut()
- .for_each(|m| m.loc.x += m.text.chars().count());
- // Find the most appropriate one to move to given the cursor position
- if let Some(mtch) = matches.first() {
- if mtch.loc.x == x {
- matches.remove(0);
+ let line = self.line(y).unwrap_or_default();
+ let words = self.word_boundaries(&line);
+ let state = self.cursor_word_state(&words, x);
+ // Work out where to move to
+ let new_x = match state {
+ // Go to start of line if at beginning
+ WordState::AtEnd(0) | WordState::InCenter(0) | WordState::AtStart(0) => 0,
+ // Cursor is at the middle / end of a word, move to previous end
+ WordState::AtEnd(idx) | WordState::InCenter(idx) => {
+ if let Some(word) = words.get(idx.saturating_sub(1)) {
+ word.1
+ } else {
+ // No previous word exists, just go to start of line
+ 0
+ }
}
- }
- if let Some(mtch) = matches.first_mut() {
- mtch.loc.y = self.loc().y;
- self.move_to(&mtch.loc);
- }
+ WordState::AtStart(idx) => {
+ // Cursor is at the start of a word, move to previous start
+ if let Some(word) = words.get(idx.saturating_sub(1)) {
+ word.0
+ } else {
+ // No previous word exists, just go to start of line
+ 0
+ }
+ }
+ WordState::Out => {
+ // Cursor is not touching any words, find previous end
+ let mut shift_back = x;
+ while let WordState::Out = self.cursor_word_state(&words, shift_back) {
+ shift_back = shift_back.saturating_sub(1);
+ if shift_back == 0 {
+ break;
+ }
+ }
+ match self.cursor_word_state(&words, shift_back) {
+ WordState::AtEnd(idx) => words[idx].1,
+ _ => 0,
+ }
+ }
+ };
+ // Perform the move
+ self.move_to_x(new_x);
+ // Clean up
self.old_cursor = self.loc().x;
Status::None
}
@@ -704,14 +758,94 @@ impl Document {
return Status::EndOfLine;
}
// Find and move to the next word
- if let Some(mut mtch) = self.next_match(r"(\s{2,}|[A-Za-z0-9_]+|$|\.)", 0) {
- mtch.loc.x += mtch.text.chars().count();
- self.move_to(&mtch.loc);
- }
+ let line = self.line(y).unwrap_or_default();
+ let words = self.word_boundaries(&line);
+ let state = self.cursor_word_state(&words, x);
+ // Work out where to move to
+ let new_x = match state {
+ // Cursor is at the middle / end of a word, move to next end
+ WordState::AtEnd(idx) | WordState::InCenter(idx) => {
+ if idx == words.len() {
+ line.chars().count()
+ } else if let Some(word) = words.get(idx + 1) {
+ word.1
+ } else {
+ // No next word exists, just go to end of line
+ line.chars().count()
+ }
+ }
+ WordState::AtStart(idx) => {
+ // Cursor is at the start of a word, move to next start
+ if idx == words.len() {
+ line.chars().count()
+ } else if let Some(word) = words.get(idx + 1) {
+ word.0
+ } else {
+ // No next word exists, just go to end of line
+ line.chars().count()
+ }
+ }
+ WordState::Out => {
+ // Cursor is not touching any words, find next start
+ let mut shift_forward = x;
+ while let WordState::Out = self.cursor_word_state(&words, shift_forward) {
+ shift_forward += 1;
+ if shift_forward == line.chars().count() {
+ break;
+ }
+ }
+ match self.cursor_word_state(&words, shift_forward) {
+ WordState::AtStart(idx) => words[idx].0,
+ _ => line.chars().count(),
+ }
+ }
+ };
+ // Perform the move
+ self.move_to_x(new_x);
+ // Clean up
self.old_cursor = self.loc().x;
Status::None
}
+ /// Function to delete a word at a certain location
+ /// # Errors
+ /// Errors if out of range
+ pub fn delete_word(&mut self) -> Result<()> {
+ let Loc { x, y } = self.char_loc();
+ let line = self.line(y).unwrap_or_default();
+ let words = self.word_boundaries(&line);
+ let state = self.cursor_word_state(&words, x);
+ let delete_upto = match state {
+ WordState::InCenter(idx) | WordState::AtEnd(idx) => {
+ // Delete back to start of this word
+ words[idx].0
+ }
+ WordState::AtStart(idx) => {
+ // Delete back to end of the previous word
+ if let Some(word) = words.get(idx.saturating_sub(1)) {
+ word.1
+ } else {
+ 0
+ }
+ }
+ WordState::Out => {
+ // Delete back to the end of the previous word
+ let mut shift_back = x;
+ while let WordState::Out = self.cursor_word_state(&words, shift_back) {
+ shift_back = shift_back.saturating_sub(1);
+ if shift_back == 0 {
+ break;
+ }
+ }
+ match self.cursor_word_state(&words, shift_back) {
+ WordState::AtEnd(idx) => words[idx].1,
+ _ => 0,
+ }
+ }
+ };
+ self.delete(delete_upto..=x, y)
+ }
+
/// Function to search the document to find the next occurance of a regex
pub fn next_match(&mut self, regex: &str, inc: usize) -> Option {
// Prepare
@@ -1210,3 +1344,11 @@ pub struct Cursor {
pub loc: Loc,
pub selection_end: Loc,
}
+
+/// State of a word
+pub enum WordState {
+ AtStart(usize),
+ AtEnd(usize),
+ InCenter(usize),
+ Out,
+}
diff --git a/kaolinite/src/searching.rs b/kaolinite/src/searching.rs
index 7df55d42..cd99a81a 100644
--- a/kaolinite/src/searching.rs
+++ b/kaolinite/src/searching.rs
@@ -4,7 +4,7 @@ use crate::utils::Loc;
use regex::Regex;
/// Stores information about a match in a document
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Match {
pub loc: Loc,
pub text: String,
diff --git a/src/config/editor.rs b/src/config/editor.rs
index 9eff3edf..6cf4c72e 100644
--- a/src/config/editor.rs
+++ b/src/config/editor.rs
@@ -135,6 +135,10 @@ impl LuaUserData for Editor {
editor.plugin_active = false;
Ok(())
});
+ methods.add_method_mut("remove_word", |_, editor, ()| {
+ let _ = editor.doc_mut().delete_word();
+ Ok(())
+ });
// Cursor moving
methods.add_method_mut("move_to", |_, editor, (x, y): (usize, usize)| {
let y = y.saturating_sub(1);
From 696c27ea821c5256bb137727e04a904036496bb0 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sun, 20 Oct 2024 15:28:13 +0100
Subject: [PATCH 19/27] Updated tests and removed redundant code
---
kaolinite/src/document.rs | 32 ++++++---------------------
kaolinite/tests/test.rs | 46 ++++++++++++++++++++++++++++++++++++---
2 files changed, 50 insertions(+), 28 deletions(-)
diff --git a/kaolinite/src/document.rs b/kaolinite/src/document.rs
index 3a32b27f..ea991ee5 100644
--- a/kaolinite/src/document.rs
+++ b/kaolinite/src/document.rs
@@ -711,21 +711,10 @@ impl Document {
WordState::AtEnd(0) | WordState::InCenter(0) | WordState::AtStart(0) => 0,
// Cursor is at the middle / end of a word, move to previous end
WordState::AtEnd(idx) | WordState::InCenter(idx) => {
- if let Some(word) = words.get(idx.saturating_sub(1)) {
- word.1
- } else {
- // No previous word exists, just go to start of line
- 0
- }
+ words[idx.saturating_sub(1)].1
}
WordState::AtStart(idx) => {
- // Cursor is at the start of a word, move to previous start
- if let Some(word) = words.get(idx.saturating_sub(1)) {
- word.0
- } else {
- // No previous word exists, just go to start of line
- 0
- }
+ words[idx.saturating_sub(1)].0
}
WordState::Out => {
// Cursor is not touching any words, find previous end
@@ -765,9 +754,7 @@ impl Document {
let new_x = match state {
// Cursor is at the middle / end of a word, move to next end
WordState::AtEnd(idx) | WordState::InCenter(idx) => {
- if idx == words.len() {
- line.chars().count()
- } else if let Some(word) = words.get(idx + 1) {
+ if let Some(word) = words.get(idx + 1) {
word.1
} else {
// No next word exists, just go to end of line
@@ -776,9 +763,7 @@ impl Document {
}
WordState::AtStart(idx) => {
// Cursor is at the start of a word, move to next start
- if idx == words.len() {
- line.chars().count()
- } else if let Some(word) = words.get(idx + 1) {
+ if let Some(word) = words.get(idx + 1) {
word.0
} else {
// No next word exists, just go to end of line
@@ -790,7 +775,7 @@ impl Document {
let mut shift_forward = x;
while let WordState::Out = self.cursor_word_state(&words, shift_forward) {
shift_forward += 1;
- if shift_forward == line.chars().count() {
+ if shift_forward >= line.chars().count() {
break;
}
}
@@ -820,13 +805,10 @@ impl Document {
// Delete back to start of this word
words[idx].0
}
+ WordState::AtStart(0) => 0,
WordState::AtStart(idx) => {
// Delete back to end of the previous word
- if let Some(word) = words.get(idx.saturating_sub(1)) {
- word.1
- } else {
- 0
- }
+ words[idx.saturating_sub(1)].1
}
WordState::Out => {
// Delete back to the end of the previous word
diff --git a/kaolinite/tests/test.rs b/kaolinite/tests/test.rs
index 230db8e5..b9e2d534 100644
--- a/kaolinite/tests/test.rs
+++ b/kaolinite/tests/test.rs
@@ -369,6 +369,33 @@ fn document_deletion() {
assert_eq!(doc.line(0), Some(st!("好")));
doc.exe(Event::Delete(Loc { x: 10000, y: 0 }, st!(" ")));
assert_eq!(doc.line(0), Some(st!("好")));
+ // Word deleting
+ doc.exe(Event::InsertLine(1, st!(" hello -world---")));
+ doc.move_to(&Loc { x: 0, y: 1 });
+ doc.delete_word();
+ assert_eq!(doc.line(1).unwrap(), st!(" hello -world---"));
+ doc.move_to(&Loc { x: 4, y: 1 });
+ doc.delete_word();
+ assert_eq!(doc.line(1).unwrap(), st!("hello -world---"));
+ doc.move_to(&Loc { x: 4, y: 1 });
+ doc.delete_word();
+ assert_eq!(doc.line(1).unwrap(), st!("o -world---"));
+ doc.move_to(&Loc { x: 1, y: 1 });
+ doc.delete_word();
+ assert_eq!(doc.line(1).unwrap(), st!(" -world---"));
+ doc.move_to(&Loc { x: 8, y: 1 });
+ doc.delete_word();
+ assert_eq!(doc.line(1).unwrap(), st!(" -world--"));
+ doc.move_to(&Loc { x: 1, y: 1 });
+ doc.delete_word();
+ assert_eq!(doc.line(1).unwrap(), st!("-world--"));
+ doc.move_to(&Loc { x: 1, y: 1 });
+ doc.delete_word();
+ assert_eq!(doc.line(1).unwrap(), st!("world--"));
+ doc.exe(Event::InsertLine(1, st!(" hello -world---")));
+ doc.move_to(&Loc { x: 11, y: 1 });
+ doc.delete_word();
+ assert_eq!(doc.line(1).unwrap(), st!(" helloworld---"));
}
#[test]
@@ -545,11 +572,11 @@ fn document_moving() {
doc.exe(Event::InsertLine(10, st!("these are words this.is.code()")));
doc.move_to(&Loc { x: 0, y: 10 });
doc.move_next_word();
- assert_eq!(doc.loc(), Loc { x: 5, y: 10 });
+ assert_eq!(doc.loc(), Loc { x: 6, y: 10 });
doc.move_next_word();
- assert_eq!(doc.loc(), Loc { x: 9, y: 10 });
+ assert_eq!(doc.loc(), Loc { x: 10, y: 10 });
doc.move_next_word();
- assert_eq!(doc.loc(), Loc { x: 15, y: 10 });
+ assert_eq!(doc.loc(), Loc { x: 16, y: 10 });
doc.move_next_word();
assert_eq!(doc.loc(), Loc { x: 20, y: 10 });
doc.move_next_word();
@@ -582,6 +609,10 @@ fn document_moving() {
doc.move_prev_word();
assert_eq!(doc.loc(), Loc { x: 0, y: 10 });
assert_eq!(doc.move_prev_word(), Status::StartOfLine);
+ doc.exe(Event::InsertLine(11, st!("----test")));
+ doc.move_to(&Loc { x: 7, y: 11 });
+ doc.move_next_word();
+ assert_eq!(doc.loc(), Loc { x: 8, y: 11 });
}
#[test]
@@ -793,6 +824,15 @@ fn document_searching() {
text: st!(" hello")
})
);
+ // General searching stuff
+ let mut searcher = Searcher::new("[0-9]+");
+ assert_eq!(
+ searcher.rfinds("hello098hello765hello"),
+ vec![
+ Match { loc: Loc { x: 13, y: 0 }, text: "765".to_string() },
+ Match { loc: Loc { x: 5, y: 0 }, text: "098".to_string() },
+ ],
+ );
}
#[test]
From acf6b404c8f3c6e2b6d569865a72351f8a6b2421 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sun, 20 Oct 2024 15:28:29 +0100
Subject: [PATCH 20/27] rustfmt
---
kaolinite/src/document.rs | 8 ++------
kaolinite/tests/test.rs | 10 ++++++++--
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/kaolinite/src/document.rs b/kaolinite/src/document.rs
index ea991ee5..286d585b 100644
--- a/kaolinite/src/document.rs
+++ b/kaolinite/src/document.rs
@@ -710,12 +710,8 @@ impl Document {
// Go to start of line if at beginning
WordState::AtEnd(0) | WordState::InCenter(0) | WordState::AtStart(0) => 0,
// Cursor is at the middle / end of a word, move to previous end
- WordState::AtEnd(idx) | WordState::InCenter(idx) => {
- words[idx.saturating_sub(1)].1
- }
- WordState::AtStart(idx) => {
- words[idx.saturating_sub(1)].0
- }
+ WordState::AtEnd(idx) | WordState::InCenter(idx) => words[idx.saturating_sub(1)].1,
+ WordState::AtStart(idx) => words[idx.saturating_sub(1)].0,
WordState::Out => {
// Cursor is not touching any words, find previous end
let mut shift_back = x;
diff --git a/kaolinite/tests/test.rs b/kaolinite/tests/test.rs
index b9e2d534..c55aafd9 100644
--- a/kaolinite/tests/test.rs
+++ b/kaolinite/tests/test.rs
@@ -829,8 +829,14 @@ fn document_searching() {
assert_eq!(
searcher.rfinds("hello098hello765hello"),
vec![
- Match { loc: Loc { x: 13, y: 0 }, text: "765".to_string() },
- Match { loc: Loc { x: 5, y: 0 }, text: "098".to_string() },
+ Match {
+ loc: Loc { x: 13, y: 0 },
+ text: "765".to_string()
+ },
+ Match {
+ loc: Loc { x: 5, y: 0 },
+ text: "098".to_string()
+ },
],
);
}
From e84e98fb53d683cb63a6b9403e22e41451228ea5 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Sun, 20 Oct 2024 23:50:49 +0100
Subject: [PATCH 21/27] updated to fit new synoptic version and config
assistant can enable icons in git
---
Cargo.lock | 4 ++--
Cargo.toml | 2 +-
plugins/git.lua | 4 ++--
src/config/assistant.rs | 3 +++
src/editor/interface.rs | 4 ++--
5 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 099fcd30..c7cabcb6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -591,9 +591,9 @@ dependencies = [
[[package]]
name = "synoptic"
-version = "2.1.0"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97419cc9b1e79552ca0622b66093fc5217d9b0048415f2c8680a52be2fcd41f7"
+checksum = "43bd6803459770f73e455673c24d25751b808f8ea77b9fa0df0672d0ecdce5dd"
dependencies = [
"if_chain",
"regex",
diff --git a/Cargo.toml b/Cargo.toml
index b118568f..3946d33c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -41,4 +41,4 @@ kaolinite = { path = "./kaolinite" }
mlua = { version = "0.9.9", features = ["lua54", "vendored"] }
quick-error = "2.0.1"
shellexpand = "3.1.0"
-synoptic = "2"
+synoptic = "2.2.0"
diff --git a/plugins/git.lua b/plugins/git.lua
index 61daa735..2848659b 100644
--- a/plugins/git.lua
+++ b/plugins/git.lua
@@ -1,5 +1,5 @@
--[[
-Git v0.2
+Git v0.3
A plug-in for git integration that provides features to:
- Choose which files to add to a commit
@@ -12,7 +12,7 @@ A plug-in for git integration that provides features to:
git = {
status = {},
- icons = false,
+ icons = (git or { icons = false }).icons,
has_git = shell:output("git --version"):find("git version"),
}
diff --git a/src/config/assistant.rs b/src/config/assistant.rs
index 0c64b2bd..db1f8c81 100644
--- a/src/config/assistant.rs
+++ b/src/config/assistant.rs
@@ -765,6 +765,9 @@ impl Assistant {
result += "\n-- Load Plug-Ins --\n";
for plugin in &self.plugins {
result += &plugin.to_config();
+ if plugin == &Plugin::Git {
+ result += "git = { icons = true }";
+ }
}
// Ready to go
result
diff --git a/src/editor/interface.rs b/src/editor/interface.rs
index b881c19c..9b39c0ca 100644
--- a/src/editor/interface.rs
+++ b/src/editor/interface.rs
@@ -11,7 +11,7 @@ use crossterm::{
};
use kaolinite::utils::{file_or_dir, get_cwd, get_parent, list_dir, width, Loc, Size};
use mlua::Lua;
-use synoptic::{trim, Highlighter, TokOpt};
+use synoptic::{trim_fit, Highlighter, TokOpt};
use super::Editor;
@@ -117,7 +117,7 @@ impl Editor {
let idx = y as usize + self.doc().offset.y;
if let Some(line) = self.doc().line(idx) {
let tokens = self.highlighter().line(idx, &line);
- let tokens = trim(&tokens, self.doc().offset.x, required_width, tab_width);
+ let tokens = trim_fit(&tokens, self.doc().offset.x, required_width, tab_width);
let mut x_pos = self.doc().offset.x;
for token in tokens {
// Find out the text (and colour of that text)
From 0a789da0b30d208f1c2aa8b8a72b49dd7ac6d0c5 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Mon, 21 Oct 2024 13:05:32 +0100
Subject: [PATCH 22/27] Fixed some issues with the configuration assistant
---
src/config/assistant.rs | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/config/assistant.rs b/src/config/assistant.rs
index db1f8c81..a0211b4a 100644
--- a/src/config/assistant.rs
+++ b/src/config/assistant.rs
@@ -75,7 +75,7 @@ Git - View and manage your git repository - requires git to be installed
Pomodoro - A timer that helps you track your periods of work and breaks
Todo - Makes .todo files interactive todo lists
Typing Speed - Shows the rough speed that you're typing in the status line
-Update Notification - Warns you if there is a new version of Ox - requires curl to be installed on unix based systems\n
+Update Notification - Warns you if there is a new version of Ox - requires curl to be installed on unix based systems
";
const FINAL_WORDS: &str = r"
@@ -106,7 +106,6 @@ pub enum Theme {
Galaxy,
Transparent,
Default,
- //Custom(HashMap),
}
impl Theme {
@@ -684,7 +683,7 @@ impl Assistant {
}
}
// Configuration of line numbers
- if sections.contains(&"line_number") {
+ if sections.contains(&"line_numbers") {
result += "\n-- Line Number Configuration --\n";
if fields.contains(&"line_numbers") {
result += &format!("line_numbers.enabled = {}\n", self.line_numbers);
From 8b5b9d366b534e00095149232e5fb0b123a6b7b7 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Tue, 22 Oct 2024 17:17:06 +0100
Subject: [PATCH 23/27] Changed around delete word command and changed galaxy
theme slightly
---
kaolinite/src/document.rs | 11 +++++++----
src/themes/galaxy.lua | 2 +-
test.txt | 2 ++
3 files changed, 10 insertions(+), 5 deletions(-)
create mode 100644 test.txt
diff --git a/kaolinite/src/document.rs b/kaolinite/src/document.rs
index 286d585b..4d550758 100644
--- a/kaolinite/src/document.rs
+++ b/kaolinite/src/document.rs
@@ -803,8 +803,8 @@ impl Document {
}
WordState::AtStart(0) => 0,
WordState::AtStart(idx) => {
- // Delete back to end of the previous word
- words[idx.saturating_sub(1)].1
+ // Delete back to start of the previous word
+ words[idx.saturating_sub(1)].0
}
WordState::Out => {
// Delete back to the end of the previous word
@@ -815,8 +815,11 @@ impl Document {
break;
}
}
- match self.cursor_word_state(&words, shift_back) {
- WordState::AtEnd(idx) => words[idx].1,
+ match (line.chars().nth(shift_back), self.cursor_word_state(&words, shift_back)) {
+ // Shift to start of previous word if there is a space
+ (Some(' '), WordState::AtEnd(idx)) => words[idx].0,
+ // Shift to end of previous word if there is not a space
+ (_, WordState::AtEnd(idx)) => words[idx].1,
_ => 0,
}
}
diff --git a/src/themes/galaxy.lua b/src/themes/galaxy.lua
index 40f39ea3..b9540372 100644
--- a/src/themes/galaxy.lua
+++ b/src/themes/galaxy.lua
@@ -32,7 +32,7 @@ colors.tab_active_bg = grey2
colors.tab_active_fg = purple
colors.info_bg = black
-colors.info_fg = lightblue
+colors.info_fg = darkblue
colors.warning_bg = black
colors.warning_fg = yellow
colors.error_bg = black
diff --git a/test.txt b/test.txt
new file mode 100644
index 00000000..4f4eb59d
--- /dev/null
+++ b/test.txt
@@ -0,0 +1,2 @@
+hello world my name is luke
+this::is::code
From 1a3f11b63144b4b3106b094fe573b41bd741c005 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Tue, 22 Oct 2024 17:21:03 +0100
Subject: [PATCH 24/27] Updated tests and rustfmt
---
kaolinite/src/document.rs | 4 +++-
kaolinite/tests/test.rs | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/kaolinite/src/document.rs b/kaolinite/src/document.rs
index 4d550758..2ac2ae7d 100644
--- a/kaolinite/src/document.rs
+++ b/kaolinite/src/document.rs
@@ -815,7 +815,9 @@ impl Document {
break;
}
}
- match (line.chars().nth(shift_back), self.cursor_word_state(&words, shift_back)) {
+ let char = line.chars().nth(shift_back);
+ let state = self.cursor_word_state(&words, shift_back);
+ match (char, state) {
// Shift to start of previous word if there is a space
(Some(' '), WordState::AtEnd(idx)) => words[idx].0,
// Shift to end of previous word if there is not a space
diff --git a/kaolinite/tests/test.rs b/kaolinite/tests/test.rs
index c55aafd9..83b316f2 100644
--- a/kaolinite/tests/test.rs
+++ b/kaolinite/tests/test.rs
@@ -395,7 +395,7 @@ fn document_deletion() {
doc.exe(Event::InsertLine(1, st!(" hello -world---")));
doc.move_to(&Loc { x: 11, y: 1 });
doc.delete_word();
- assert_eq!(doc.line(1).unwrap(), st!(" helloworld---"));
+ assert_eq!(doc.line(1).unwrap(), st!(" world---"));
}
#[test]
From bd7cd1cd444fefa943caede30eae543d9c42f827 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Tue, 22 Oct 2024 20:01:01 +0100
Subject: [PATCH 25/27] Fixed python syntax highlighting
---
Cargo.lock | 4 ++--
Cargo.toml | 2 +-
test.txt | 2 --
3 files changed, 3 insertions(+), 5 deletions(-)
delete mode 100644 test.txt
diff --git a/Cargo.lock b/Cargo.lock
index c7cabcb6..b97821ce 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -591,9 +591,9 @@ dependencies = [
[[package]]
name = "synoptic"
-version = "2.2.0"
+version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43bd6803459770f73e455673c24d25751b808f8ea77b9fa0df0672d0ecdce5dd"
+checksum = "b0ed930df773aaac411d90bbf1e20b1538514c981f0dc1231f5feea1ef2910f0"
dependencies = [
"if_chain",
"regex",
diff --git a/Cargo.toml b/Cargo.toml
index 3946d33c..775bc1d8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -41,4 +41,4 @@ kaolinite = { path = "./kaolinite" }
mlua = { version = "0.9.9", features = ["lua54", "vendored"] }
quick-error = "2.0.1"
shellexpand = "3.1.0"
-synoptic = "2.2.0"
+synoptic = "2.2.1"
diff --git a/test.txt b/test.txt
deleted file mode 100644
index 4f4eb59d..00000000
--- a/test.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-hello world my name is luke
-this::is::code
From 6d3b4d17afdb5b1b78f07878cce547e5e73e04cb Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Tue, 22 Oct 2024 21:18:07 +0100
Subject: [PATCH 26/27] Fixed rendering issues in greeting message and changed
its position
---
src/editor/interface.rs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/editor/interface.rs b/src/editor/interface.rs
index 9b39c0ca..c44b29f8 100644
--- a/src/editor/interface.rs
+++ b/src/editor/interface.rs
@@ -75,7 +75,8 @@ impl Editor {
}
})
.collect::>();
- let start = u16::try_from(h / 4).unwrap_or(u16::MAX);
+ let first_line = (h / 2).saturating_sub(message.len() / 2) + 1;
+ let start = u16::try_from(first_line).unwrap_or(u16::MAX);
let end = start + u16::try_from(message.len()).unwrap_or(u16::MAX);
// Render each line of the document
for y in 0..u16::try_from(h).unwrap_or(0) {
@@ -160,7 +161,10 @@ impl Editor {
// Render help message if applicable (otherwise, just output padding to clear buffer)
if self.config.help_message.borrow().enabled && (start..=end).contains(&y) {
let idx = y.saturating_sub(start);
- display!(self, message.get(idx as usize).unwrap_or(&String::new()));
+ let line = message
+ .get(idx as usize)
+ .map_or(" ".repeat(max_width), |s| s.to_string());
+ display!(self, line, " ".repeat(max_width));
}
}
Ok(())
From 6bdf62a90436589740f95862432190a82b672be4 Mon Sep 17 00:00:00 2001
From: Luke <11898833+curlpipe@users.noreply.github.com>
Date: Tue, 22 Oct 2024 21:53:25 +0100
Subject: [PATCH 27/27] Update README.md
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index d6c85164..566ecc66 100644
--- a/README.md
+++ b/README.md
@@ -55,6 +55,7 @@ It is mainly used on linux systems, but macOS and Windows users (via WSL) are fr
- :electric_plug: Plug-In system where you can write your own plug-ins or integrate other people's
- :wrench: A wide number of options for configuration with everything from colours to the status line to syntax highlighting being open to customisation
- :moon: Ox uses Lua as a configuration language for familiarity when scripting and configuring
+- 🤝 A configuration assistant to quickly get Ox set up for you from the get-go
### Out of the box features