Skip to content

Commit 39ba0df

Browse files
authored
Merge pull request #168 from curlpipe/dev
0.6.6
2 parents d5b4bf8 + 1a4d8c3 commit 39ba0df

File tree

22 files changed

+1207
-215
lines changed

22 files changed

+1207
-215
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ exclude = ["cactus"]
77

88
[package]
99
name = "ox"
10-
version = "0.6.5"
10+
version = "0.6.6"
1111
edition = "2021"
1212
authors = ["Curlpipe <[email protected]>"]
1313
description = "A Rust powered text editor."

config/.oxrc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@ commands = {
180180
end
181181
end,
182182
["filetype"] = function(arguments)
183-
ext = arguments[1]
184-
editor:set_file_type(ext)
183+
local file_type_name = arguments[1]
184+
editor:set_file_type(file_type_name)
185185
end,
186186
["reload"] = function(arguments)
187187
editor:reload_config()

kaolinite/src/document.rs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -767,10 +767,6 @@ impl Document {
767767
/// Function to select to a specific x position
768768
pub fn select_to_x(&mut self, x: usize) {
769769
let line = self.line(self.loc().y).unwrap_or_default();
770-
// If we're already at this x coordinate, just exit
771-
if self.char_ptr == x {
772-
return;
773-
}
774770
// If the move position is out of bounds, move to the end of the line
775771
if line.chars().count() < x {
776772
let line = self.line(self.loc().y).unwrap_or_default();
@@ -810,6 +806,43 @@ impl Document {
810806
self.load_to(self.offset.y + self.size.h);
811807
}
812808

809+
/// Select a word at a location
810+
pub fn select_word_at(&mut self, loc: &Loc) {
811+
let y = loc.y;
812+
let x = self.character_idx(loc);
813+
let re = format!("(\t| {{{}}}|^|\\W| )", self.tab_width);
814+
let start = if let Some(mut mtch) = self.prev_match(&re) {
815+
let len = mtch.text.chars().count();
816+
let same = mtch.loc.x + len == x;
817+
if !same {
818+
mtch.loc.x += len;
819+
}
820+
self.move_to(&mtch.loc);
821+
if same && self.loc().x != 0 {
822+
self.move_prev_word();
823+
}
824+
mtch.loc.x
825+
} else {
826+
0
827+
};
828+
let re = format!("(\t| {{{}}}|\\W|$|^ +| )", self.tab_width);
829+
let end = if let Some(mtch) = self.next_match(&re, 0) {
830+
mtch.loc.x
831+
} else {
832+
self.line(y).unwrap_or_default().chars().count()
833+
};
834+
self.move_to(&Loc { x: start, y });
835+
self.select_to(&Loc { x: end, y });
836+
self.old_cursor = self.loc().x;
837+
}
838+
839+
/// Select a line at a location
840+
pub fn select_line_at(&mut self, y: usize) {
841+
let len = self.line(y).unwrap_or_default().chars().count();
842+
self.move_to(&Loc { x: 0, y });
843+
self.select_to(&Loc { x: len, y });
844+
}
845+
813846
/// Brings the cursor into the viewport so it can be seen
814847
pub fn bring_cursor_in_viewport(&mut self) {
815848
if self.offset.y > self.cursor.loc.y {

kaolinite/tests/test.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,27 @@ fn document_selection() {
605605
assert!(!doc.is_loc_selected(Loc { x: 0, y: 0 }));
606606
assert!(!doc.is_loc_selected(Loc { x: 2, y: 0 }));
607607
assert!(!doc.is_loc_selected(Loc { x: 3, y: 0 }));
608+
doc.select_line_at(1);
609+
assert_eq!(
610+
doc.selection_loc_bound(),
611+
(Loc { x: 0, y: 1 }, Loc { x: 31, y: 1 })
612+
);
613+
doc.remove_selection();
614+
doc.exe(Event::InsertLine(1, "hello there world".to_string()));
615+
doc.exe(Event::InsertLine(2, "hello".to_string()));
616+
doc.move_to(&Loc { x: 8, y: 1 });
617+
doc.select_word_at(&Loc { x: 8, y: 1 });
618+
assert_eq!(
619+
doc.selection_loc_bound(),
620+
(Loc { x: 6, y: 1 }, Loc { x: 11, y: 1 })
621+
);
622+
doc.remove_selection();
623+
doc.move_to(&Loc { x: 0, y: 2 });
624+
doc.select_word_at(&Loc { x: 0, y: 2 });
625+
assert_eq!(
626+
doc.selection_loc_bound(),
627+
(Loc { x: 0, y: 2 }, Loc { x: 5, y: 2 })
628+
);
608629
}
609630

610631
#[test]

plugins/autoindent.lua

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--[[
2-
Auto Indent v0.7
2+
Auto Indent v0.8
33
44
Helps you when programming by guessing where indentation should go
55
and then automatically applying these guesses as you program
@@ -170,10 +170,23 @@ event_mapping["enter"] = function()
170170
autoindent:disperse_block()
171171
end
172172

173-
event_mapping["*"] = function()
174-
-- Dedent where appropriate
175-
if autoindent:causes_dedent(editor.cursor.y) then
176-
local new_level = autoindent:get_indent(editor.cursor.y) - 1
177-
autoindent:set_indent(editor.cursor.y, new_level)
173+
-- For each ascii characters and punctuation
174+
was_dedenting = false
175+
for i = 32, 126 do
176+
local char = string.char(i)
177+
-- ... excluding the global event binding
178+
if char ~= "*" then
179+
-- Keep track of whether the line was previously dedenting beforehand
180+
event_mapping["before:" .. char] = function()
181+
was_dedenting = autoindent:causes_dedent(editor.cursor.y)
182+
end
183+
-- Trigger dedent checking
184+
event_mapping[char] = function()
185+
-- Dedent where appropriate
186+
if autoindent:causes_dedent(editor.cursor.y) and not was_dedenting then
187+
local new_level = autoindent:get_indent(editor.cursor.y) - 1
188+
autoindent:set_indent(editor.cursor.y, new_level)
189+
end
190+
end
178191
end
179192
end

src/cli.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,20 @@ Ox: A lightweight and flexible text editor
1212
USAGE: ox [options] [files]
1313
1414
OPTIONS:
15-
--help, -h : Show this help message
16-
--version, -v : Show the version number
17-
--config [path], -c [path] : Specify the configuration file
18-
--readonly, -r : Prevent opened files from writing
19-
--filetype [ext], -f [ext] : Set the file type of files opened
20-
--stdin : Reads file from the stdin
15+
--help, -h : Show this help message
16+
--version, -v : Show the version number
17+
--config [path], -c [path] : Specify the configuration file
18+
--readonly, -r : Prevent opened files from writing
19+
--filetype [name], -f [name] : Set the file type of files opened
20+
--stdin : Reads file from the stdin
2121
2222
EXAMPLES:
2323
ox
2424
ox test.txt
2525
ox test.txt test2.txt
2626
ox /home/user/docs/test.txt
2727
ox -c config.lua test.txt
28-
ox -r -c ~/.config/.oxrc -f lua my_file.lua
28+
ox -r -c ~/.config/.oxrc -f Lua my_file.lua
2929
tree | ox -r --stdin\
3030
";
3131

src/config/editor.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl LuaUserData for Editor {
2424
});
2525
fields.add_field_method_get("version", |_, _| Ok(VERSION));
2626
fields.add_field_method_get("current_document_id", |_, editor| Ok(editor.ptr));
27-
fields.add_field_method_get("document_count", |_, editor| Ok(editor.doc.len()));
27+
fields.add_field_method_get("document_count", |_, editor| Ok(editor.files.len()));
2828
fields.add_field_method_get("document_type", |_, editor| {
2929
let ext = editor
3030
.doc()
@@ -437,14 +437,15 @@ impl LuaUserData for Editor {
437437
editor.doc_mut().info.read_only = status;
438438
Ok(())
439439
});
440-
methods.add_method_mut("set_file_type", |_, editor, ext: String| {
441-
let mut highlighter = editor
442-
.config
443-
.syntax_highlighting
444-
.borrow()
445-
.get_highlighter(&ext);
446-
highlighter.run(&editor.doc().lines);
447-
editor.highlighter[editor.ptr] = highlighter;
440+
methods.add_method_mut("set_file_type", |_, editor, name: String| {
441+
if let Some(file_type) = editor.config.document.borrow().file_types.get_name(&name) {
442+
let mut highlighter = file_type.get_highlighter(&editor.config, 4);
443+
highlighter.run(&editor.doc().lines);
444+
editor.files[editor.ptr].highlighter = highlighter;
445+
editor.files[editor.ptr].file_type = Some(file_type);
446+
} else {
447+
editor.feedback = Feedback::Error(format!("Invalid file type: {name}"));
448+
}
448449
Ok(())
449450
});
450451
// Rerendering

src/config/highlighting.rs

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::error::{OxError, Result};
22
use crossterm::style::Color as CColor;
33
use mlua::prelude::*;
44
use std::collections::HashMap;
5-
use synoptic::{from_extension, Highlighter};
5+
use synoptic::Highlighter;
66

77
use super::Color;
88

@@ -27,14 +27,6 @@ impl SyntaxHighlighting {
2727
)))
2828
}
2929
}
30-
31-
/// Get a highlighter given a file extension
32-
pub fn get_highlighter(&self, ext: &str) -> Highlighter {
33-
self.user_rules.get(ext).map_or_else(
34-
|| from_extension(ext, 4).unwrap_or_else(|| Highlighter::new(4)),
35-
std::clone::Clone::clone,
36-
)
37-
}
3830
}
3931

4032
impl LuaUserData for SyntaxHighlighting {
@@ -84,40 +76,36 @@ impl LuaUserData for SyntaxHighlighting {
8476
);
8577
methods.add_method_mut(
8678
"new",
87-
|_, syntax_highlighting, (extensions, rules): (LuaTable, LuaTable)| {
88-
// Make note of the highlighter
89-
for ext_idx in 1..=(extensions.len()?) {
90-
// Create highlighter
91-
let mut highlighter = Highlighter::new(4);
92-
// Add rules one by one
93-
for rule_idx in 1..=(rules.len()?) {
94-
// Get rule
95-
let rule = rules.get::<i64, HashMap<String, String>>(rule_idx)?;
96-
// Find type of rule and attatch it to the highlighter
97-
match rule["kind"].as_str() {
98-
"keyword" => {
99-
highlighter.keyword(rule["name"].clone(), &rule["pattern"]);
100-
}
101-
"bounded" => highlighter.bounded(
102-
rule["name"].clone(),
103-
rule["start"].clone(),
104-
rule["end"].clone(),
105-
rule["escape"] == "true",
106-
),
107-
"bounded_interpolation" => highlighter.bounded_interp(
108-
rule["name"].clone(),
109-
rule["start"].clone(),
110-
rule["end"].clone(),
111-
rule["i_start"].clone(),
112-
rule["i_end"].clone(),
113-
rule["escape"] == "true",
114-
),
115-
_ => unreachable!(),
79+
|_, syntax_highlighting, (name, rules): (String, LuaTable)| {
80+
// Create highlighter
81+
let mut highlighter = Highlighter::new(4);
82+
// Add rules one by one
83+
for rule_idx in 1..=(rules.len()?) {
84+
// Get rule
85+
let rule = rules.get::<i64, HashMap<String, String>>(rule_idx)?;
86+
// Find type of rule and attatch it to the highlighter
87+
match rule["kind"].as_str() {
88+
"keyword" => {
89+
highlighter.keyword(rule["name"].clone(), &rule["pattern"]);
11690
}
91+
"bounded" => highlighter.bounded(
92+
rule["name"].clone(),
93+
rule["start"].clone(),
94+
rule["end"].clone(),
95+
rule["escape"] == "true",
96+
),
97+
"bounded_interpolation" => highlighter.bounded_interp(
98+
rule["name"].clone(),
99+
rule["start"].clone(),
100+
rule["end"].clone(),
101+
rule["i_start"].clone(),
102+
rule["i_end"].clone(),
103+
rule["escape"] == "true",
104+
),
105+
_ => unreachable!(),
117106
}
118-
let ext = extensions.get::<i64, String>(ext_idx)?;
119-
syntax_highlighting.user_rules.insert(ext, highlighter);
120107
}
108+
syntax_highlighting.user_rules.insert(name, highlighter);
121109
Ok(())
122110
},
123111
);

src/config/interface.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use crate::cli::VERSION;
2-
use crate::editor::{which_extension, Editor};
2+
use crate::editor::{Editor, FileContainer};
33
use crate::error::Result;
44
use crossterm::style::SetForegroundColor as Fg;
55
use kaolinite::searching::Searcher;
6-
use kaolinite::utils::{filetype, get_absolute_path, get_file_name, icon};
7-
use kaolinite::Document;
6+
use kaolinite::utils::{get_absolute_path, get_file_ext, get_file_name};
87
use mlua::prelude::*;
98

109
use super::{issue_warning, Colors};
@@ -218,16 +217,17 @@ impl Default for TabLine {
218217

219218
impl TabLine {
220219
/// Take the configuration information and render the tab line
221-
pub fn render(&self, document: &Document) -> String {
222-
let path = document
220+
pub fn render(&self, file: &FileContainer) -> String {
221+
let path = file
222+
.doc
223223
.file_name
224224
.clone()
225225
.unwrap_or_else(|| "[No Name]".to_string());
226-
let file_extension = which_extension(document).unwrap_or_else(|| "Unknown".to_string());
226+
let file_extension = get_file_ext(&path).unwrap_or_else(|| "Unknown".to_string());
227227
let absolute_path = get_absolute_path(&path).unwrap_or_else(|| "[No Name]".to_string());
228228
let file_name = get_file_name(&path).unwrap_or_else(|| "[No Name]".to_string());
229-
let icon = icon(&filetype(&file_extension).unwrap_or_default());
230-
let modified = if document.info.modified { "[+]" } else { "" };
229+
let icon = file.file_type.clone().map_or("󰈙 ".to_string(), |t| t.icon);
230+
let modified = if file.doc.info.modified { "[+]" } else { "" };
231231
let mut result = self.format.clone();
232232
result = result
233233
.replace("{file_extension}", &file_extension)
@@ -277,23 +277,21 @@ impl Default for StatusLine {
277277
impl StatusLine {
278278
/// Take the configuration information and render the status line
279279
pub fn render(&self, editor: &Editor, lua: &Lua, w: usize) -> String {
280+
let file = &editor.files[editor.ptr];
280281
let mut result = vec![];
281282
let path = editor
282283
.doc()
283284
.file_name
284285
.clone()
285286
.unwrap_or_else(|| "[No Name]".to_string());
286-
let file_extension = which_extension(editor.doc()).unwrap_or_else(|| "Unknown".to_string());
287+
let file_extension = get_file_ext(&path).unwrap_or_else(|| "Unknown".to_string());
287288
let absolute_path = get_absolute_path(&path).unwrap_or_else(|| "[No Name]".to_string());
288289
let file_name = get_file_name(&path).unwrap_or_else(|| "[No Name]".to_string());
289-
let file_type = filetype(&file_extension).unwrap_or_else(|| {
290-
if file_extension.is_empty() {
291-
"Unknown".to_string()
292-
} else {
293-
file_extension.to_string()
294-
}
295-
});
296-
let icon = icon(&filetype(&file_extension).unwrap_or_default());
290+
let file_type = file
291+
.file_type
292+
.clone()
293+
.map_or("Unknown".to_string(), |t| t.name);
294+
let icon = file.file_type.clone().map_or("󰈙 ".to_string(), |t| t.icon);
297295
let modified = if editor.doc().info.modified {
298296
"[+]"
299297
} else {

0 commit comments

Comments
 (0)