Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support elastic tabstops #89

Open
dicktyr opened this issue Jan 15, 2025 · 2 comments
Open

support elastic tabstops #89

dicktyr opened this issue Jan 15, 2025 · 2 comments

Comments

@dicktyr
Copy link

dicktyr commented Jan 15, 2025

elastic tabstops are certainly useful and essential for working with tabular data

@adsr
Copy link
Owner

adsr commented Jan 20, 2025

Hi, thanks for the idea. If we expose an API function to set vcol, you could write this as a Lua plugin. However, I have some heavy refactoring planned for 1.8.0 that relates to how characters are stored and rendered (including vcol), so I will wait until then.

In the mean time, here's an untested proof-of-concept for a such a function.

diff --git a/uscript.inc.c b/uscript.inc.c
index 2bf55a1..bfdabf4 100644
--- a/uscript.inc.c
+++ b/uscript.inc.c
@@ -2529,6 +2529,36 @@ static int _uscript_func_mark_swap(lua_State *L) {
     return 1;
 }
 
+static int _uscript_func_mark_set_char_vwidth(lua_State *L) {
+    mark_t *mark = (mark_t *)luaL_checkpointer(L, 1);
+    bint_t new_vwidth = (bint_t)luaL_checkinteger(L, 2);
+    int rv;
+    if (new_vwidth >= 1) {
+        bline_t *bline = mark->bline;
+        bint_t cur_vwidth;
+        if (mark->col < bline->char_count - 1) {
+            cur_vwidth = bline->chars[mark->col + 1].vcol - bline->chars[mark->col].vcol;
+            bint_t col;
+            for (col = mark->col + 1; col < bline->char_count; col++) {
+                bline->chars[col].vcol += new_vwidth - cur_vwidth;
+            }
+        } else if (mark->col < bline->char_count) {
+            cur_vwidth = bline->char_vwidth - bline->chars[mark->col].vcol;
+        }
+        bline->char_vwidth += new_vwidth - cur_vwidth;
+        rv = MLE_OK;
+    } else {
+        rv = MLE_ERR;
+    }
+
+    lua_createtable(L, 0, 1);
+    lua_pushstring(L, "rv");
+    lua_pushinteger(L, (lua_Integer)rv);
+    lua_settable(L, -3);
+    lua_pushvalue(L, -1);
+    return 1;
+}
+
 // static int _uscript_func_util_escape_shell_arg(lua_State *L) {
 // }
 
@@ -2691,5 +2721,6 @@ static const struct luaL_Reg mle_lib[] = {
     { "mark_swap", _uscript_func_mark_swap },
     { "util_escape_shell_arg", _uscript_func_util_escape_shell_arg },
     { "util_shell_exec", _uscript_func_util_shell_exec },
+    { "mark_set_char_vwidth", _uscript_func_mark_set_char_vwidth },
     { NULL, NULL }
 };

And here's a contrived example that sets all tab widths equal to line_index + 1. You could use this as a starting point to implement elastic tabs.

-- vcol.lua
mle.editor_register_observer("buffer:baction", function (baction)
    local buffer = baction["buffer"]
    local sl = baction["start_line_index"]
    local el = baction["maybe_end_line_index"]
    if el < sl then el = sl end
    local mark = mle.buffer_add_mark(buffer, "0x0", 0)["rv"]
    local eol = mle.buffer_add_mark(buffer, "0x0", 0)["rv"]
    for line_index = sl, el do
        mle.mark_move_to(mark, line_index, 0)
        mle.mark_move_to(eol, line_index, 0)
        mle.mark_move_bol(mark)
        mle.mark_move_eol(eol)
        while mle.mark_move_next_str(mark, "\t", 1)["rv"] == 0 and mle.mark_is_lt(mark, eol)["rv"] > 0 do
            mle.mark_set_char_vwidth(mark, line_index + 1)
            mle.mark_move_by(mark, 1)
        end
    end
    mle.mark_destroy(mark)
    mle.mark_destroy(eol)
end)

To test it:

$ { for i in $(seq 1 9); do printf "$i\ta\tb\n"; done; } | ./mle -N -H0 -a0 -x vcol.lua

@dicktyr
Copy link
Author

dicktyr commented Jan 21, 2025

thanks for your kind reply and code

I'm not (yet?) a regular user of mle but discovered it recently
while looking for basic terminal text editors

in any case
I'm glad you appreciate elastic tabstops
(odd that they still remain so unknown)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants