Last active
March 31, 2026 03:59
-
-
Save anoduck/899b804d3d0051f5d47013b845ccef35 to your computer and use it in GitHub Desktop.
Org-mode for Jed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| % org_mode.sl - Org-mode for Jed (S-Lang) with full Babel code execution (now 11+ languages) | |
| % | |
| % NEW: Go / Golang support added (C-c C-c on #+BEGIN_SRC go) | |
| % • Uses `go run` (single-file execution, no build step needed) | |
| % • Temp file cleanup | |
| % • Captures stdout + stderr exactly like all other languages | |
| % | |
| % All previous features preserved (headlines, TODO, folding, agenda, tables, 10+ other languages, etc.). | |
| % | |
| % Install: ~/.jed/lib/org_mode.sl then in .jedrc: | |
| % require("org_mode"); | |
| % add_mode_for_extension("org", "org"); | |
| provide("org_mode"); | |
| require("mode"); | |
| require("folding"); | |
| require("syntax"); | |
| % =================================================================== | |
| % Customizable variables | |
| % =================================================================== | |
| variable Org_Todo_Keywords = ["TODO", "NEXT", "WAITING", "DONE", "CANCELLED"]; | |
| variable Org_Headline_Levels = 8; | |
| % =================================================================== | |
| % Helper: run shell command and capture output | |
| % =================================================================== | |
| static define org_run_shell_cmd(cmd) | |
| { | |
| variable p, line, output = ""; | |
| p = popen(cmd, "r"); | |
| if (p == NULL) | |
| return "ERROR: popen failed (command not found?)"; | |
| while (fgets(line, p) != NULL) | |
| output += line; | |
| () = fclose(p); | |
| return strtrim(output); | |
| } | |
| % =================================================================== | |
| % Syntax highlighting (unchanged) | |
| % =================================================================== | |
| static define org_highlight() | |
| { | |
| syntax_clear(); | |
| % Headlines | |
| for (integer i = 1; i <= Org_Headline_Levels; i++) | |
| syntax_add_keyword("org_headline", | |
| "^" + str_repeat("\\*", i) + " ", Keyword_Color); | |
| % TODO keywords (bold) | |
| foreach (string kw in Org_Todo_Keywords) | |
| syntax_add_keyword("org_todo", kw, Keyword_Color | 0x08); | |
| % Tags | |
| syntax_add_keyword("org_tag", ":[A-Za-z0-9_@]+(:[A-Za-z0-9_@]+)*:", String_Color); | |
| % Links | |
| syntax_add_keyword("org_link", "\\[\\[.+?\\]\\]", String_Color | 0x04); | |
| % Tables | |
| syntax_add_keyword("org_table", "^\\s*|", Comment_Color); | |
| % Source blocks & results | |
| syntax_add_keyword("org_block", "^\\s*#\\+BEGIN_SRC", Keyword_Color); | |
| syntax_add_keyword("org_block", "^\\s*#\\+END_SRC", Keyword_Color); | |
| syntax_add_keyword("org_block", "^\\s*#\\+RESULTS:", Comment_Color); | |
| % Drawers / comments | |
| syntax_add_keyword("org_drawer", "^\\s*:\\w+:", Comment_Color); | |
| syntax_add_keyword("org_comment", "^\\s*# ", Comment_Color); | |
| set_syntax_flags(SYNTAX_COMMENTS | SYNTAX_STRINGS); | |
| } | |
| % =================================================================== | |
| % Visibility cycling (TAB) | |
| % =================================================================== | |
| static define org_is_headline() | |
| { | |
| return re_match(what_line(), "^\\*+ "); | |
| } | |
| static define org_get_level() | |
| { | |
| variable m = re_match(what_line(), "^(\\*+) "); | |
| return (m == NULL) ? 0 : strlen(m[1]); | |
| } | |
| static define org_cycle_visibility() | |
| { | |
| if (!org_is_headline()) | |
| { | |
| self_insert_key(); | |
| return; | |
| } | |
| if (folding_is_folded()) | |
| folding_unfold(); | |
| else | |
| folding_fold(); | |
| } | |
| % =================================================================== | |
| % TODO cycling (C-c C-t) | |
| % =================================================================== | |
| static define org_todo_cycle() | |
| { | |
| variable line = what_line(); | |
| variable pos = strfind(line, "TODO") > -1 ? strfind(line, "TODO") : | |
| (strfind(line, "DONE") > -1 ? strfind(line, "DONE") : -1); | |
| if (pos == -1) | |
| { | |
| bol(); insert("TODO "); | |
| return; | |
| } | |
| if (strfind(line, "TODO") != -1) | |
| replace("TODO", "DONE"); | |
| else if (strfind(line, "DONE") != -1) | |
| replace("DONE", "TODO"); | |
| } | |
| % =================================================================== | |
| % Simple agenda (C-c a) | |
| % =================================================================== | |
| static define org_agenda() | |
| { | |
| pop2buf("*Org Agenda*"); | |
| erase_buffer(); | |
| insert("=== Org Agenda (TODOs in current buffer) ===\n\n"); | |
| push_mark(); bob(); | |
| while (re_search_forward("^\\*+ .*\\(TODO\\|NEXT\\|WAITING\\)")) | |
| insert(what_line() + "\n"); | |
| bob(); pop_mark(0); | |
| message("Agenda ready. Press q to quit."); | |
| } | |
| % =================================================================== | |
| % Table alignment stub | |
| % =================================================================== | |
| static define org_table_align() | |
| { | |
| if (!re_match(what_line(), "^\\s*|")) | |
| return; | |
| message("Table aligned (full parser stub – extend if needed)."); | |
| } | |
| % =================================================================== | |
| % Babel: extract current #+BEGIN_SRC block (unchanged) | |
| % =================================================================== | |
| static define org_extract_src_block() | |
| { | |
| variable block_start = 0, block_end = 0, lang = "", code = ""; | |
| push_spot(); | |
| while (up_1()) | |
| { | |
| variable line = what_line(); | |
| if (re_match(line, "^\\s*#\\+BEGIN_SRC\\s+(\\S+)", 1)) | |
| { | |
| block_start = what_line_number(); | |
| lang = string_match_nth(1); | |
| break; | |
| } | |
| } | |
| if (block_start == 0) | |
| { | |
| pop_spot(); | |
| return NULL; | |
| } | |
| goto_line(block_start); | |
| while (down_1()) | |
| { | |
| if (re_match(what_line(), "^\\s*#\\+END_SRC", 1)) | |
| { | |
| block_end = what_line_number(); | |
| break; | |
| } | |
| } | |
| pop_spot(); | |
| if (block_end == 0) | |
| return NULL; | |
| goto_line(block_start + 1); | |
| while (what_line_number() < block_end) | |
| { | |
| code += what_line() + "\n"; | |
| down_1(); | |
| } | |
| return struct {lang = strtrim(lang), code = strtrim(code)}; | |
| } | |
| % =================================================================== | |
| % Babel: execute current block – NOW WITH Go/Golang (C-c C-c) | |
| % =================================================================== | |
| static define org_babel_execute() | |
| { | |
| variable block = org_extract_src_block(); | |
| if (block == NULL) | |
| { | |
| message("Cursor must be inside a #+BEGIN_SRC ... #+END_SRC block"); | |
| return; | |
| } | |
| variable lang = block.lang; | |
| variable code = block.code; | |
| if (ask_yesno(sprintf("Execute %s block? (y/n)", lang)) != 1) | |
| { | |
| message("Babel execution aborted."); | |
| return; | |
| } | |
| variable tmp = "/tmp/jed_org_babel_" + string(_time()); | |
| variable result = "", cmd = "", ext = ""; | |
| switch (lang) | |
| { | |
| case "python": | |
| case "python3": | |
| ext = ".py"; | |
| variable f = fopen(tmp + ext, "w"); | |
| fputs(code, f); fclose(f); | |
| result = org_run_shell_cmd("python3 " + tmp + ext + " 2>&1"); | |
| () = delete_file(tmp + ext); | |
| break; | |
| case "shell": | |
| case "bash": | |
| case "sh": | |
| result = org_run_shell_cmd(code); | |
| break; | |
| case "javascript": | |
| case "js": | |
| ext = ".js"; | |
| f = fopen(tmp + ext, "w"); | |
| fputs(code, f); fclose(f); | |
| result = org_run_shell_cmd("node " + tmp + ext + " 2>&1"); | |
| () = delete_file(tmp + ext); | |
| break; | |
| case "ruby": | |
| ext = ".rb"; | |
| f = fopen(tmp + ext, "w"); | |
| fputs(code, f); fclose(f); | |
| result = org_run_shell_cmd("ruby " + tmp + ext + " 2>&1"); | |
| () = delete_file(tmp + ext); | |
| break; | |
| case "perl": | |
| ext = ".pl"; | |
| f = fopen(tmp + ext, "w"); | |
| fputs(code, f); fclose(f); | |
| result = org_run_shell_cmd("perl " + tmp + ext + " 2>&1"); | |
| () = delete_file(tmp + ext); | |
| break; | |
| case "lua": | |
| ext = ".lua"; | |
| f = fopen(tmp + ext, "w"); | |
| fputs(code, f); fclose(f); | |
| result = org_run_shell_cmd("lua " + tmp + ext + " 2>&1"); | |
| () = delete_file(tmp + ext); | |
| break; | |
| case "julia": | |
| ext = ".jl"; | |
| f = fopen(tmp + ext, "w"); | |
| fputs(code, f); fclose(f); | |
| result = org_run_shell_cmd("julia " + tmp + ext + " 2>&1"); | |
| () = delete_file(tmp + ext); | |
| break; | |
| case "R": | |
| case "r": | |
| ext = ".R"; | |
| f = fopen(tmp + ext, "w"); | |
| fputs(code, f); fclose(f); | |
| result = org_run_shell_cmd("Rscript " + tmp + ext + " 2>&1"); | |
| () = delete_file(tmp + ext); | |
| break; | |
| case "C": | |
| case "c": | |
| ext = ".c"; | |
| f = fopen(tmp + ext, "w"); | |
| fputs(code, f); fclose(f); | |
| result = org_run_shell_cmd("gcc -x c -o " + tmp + " " + tmp + ext + " 2>&1 && " + tmp + " 2>&1"); | |
| () = delete_file(tmp + ext); | |
| () = delete_file(tmp); | |
| break; | |
| case "cpp": | |
| case "C++": | |
| ext = ".cpp"; | |
| f = fopen(tmp + ext, "w"); | |
| fputs(code, f); fclose(f); | |
| result = org_run_shell_cmd("g++ -x c++ -o " + tmp + " " + tmp + ext + " 2>&1 && " + tmp + " 2>&1"); | |
| () = delete_file(tmp + ext); | |
| () = delete_file(tmp); | |
| break; | |
| case "haskell": | |
| ext = ".hs"; | |
| f = fopen(tmp + ext, "w"); | |
| fputs(code, f); fclose(f); | |
| result = org_run_shell_cmd("runghc " + tmp + ext + " 2>&1"); | |
| () = delete_file(tmp + ext); | |
| break; | |
| % ==================== NEW: GO / GOLANG ==================== | |
| case "go": | |
| case "golang": | |
| ext = ".go"; | |
| f = fopen(tmp + ext, "w"); | |
| fputs(code, f); fclose(f); | |
| result = org_run_shell_cmd("go run " + tmp + ext + " 2>&1"); | |
| () = delete_file(tmp + ext); | |
| break; | |
| % ========================================================== | |
| default: | |
| message("Language '" + lang + "' not supported yet. Add it to org_babel_execute switch."); | |
| return; | |
| } | |
| % Insert / replace #+RESULTS: right after #+END_SRC | |
| re_search_forward("^\\s*#\\+END_SRC"); | |
| eol(); | |
| insert("\n#+RESULTS:\n" + result + "\n"); | |
| message(sprintf("%s block executed – results inserted.", lang)); | |
| } | |
| % =================================================================== | |
| % Keymap | |
| % =================================================================== | |
| static define org_keymap() | |
| { | |
| variable km = "Org"; | |
| definekey("org_cycle_visibility", "^I", km); % TAB | |
| definekey("org_todo_cycle", "^C^T", km); % C-c C-t | |
| definekey("org_agenda", "^C^A", km); % C-c a | |
| definekey("org_table_align", "^I", km); % TAB in tables | |
| definekey("org_babel_execute", "^C^C", km); % C-c C-c | |
| % Navigation | |
| definekey("outline_next_heading", "^C^N", km); | |
| definekey("outline_previous_heading", "^C^P", km); | |
| definekey("outline_forward_same_level", "^C^F", km); | |
| definekey("outline_backward_same_level", "^C^B", km); | |
| menu_add_item("&Org", "&Cycle TODO", "org_todo_cycle"); | |
| menu_add_item("&Org", "&Agenda", "org_agenda"); | |
| menu_add_item("&Org", "Execute &Babel Block", "org_babel_execute"); | |
| } | |
| % =================================================================== | |
| % Mode entry | |
| % =================================================================== | |
| define org_mode() | |
| { | |
| set_mode("Org"); | |
| use_keymap("Org"); | |
| org_highlight(); | |
| folding_mode(); | |
| % Auto-mark fold points for headlines | |
| push_mark(); bob(); | |
| while (re_search_forward("^\\*+ ")) | |
| folding_mark(); | |
| pop_mark(0); bob(); | |
| run_mode_hooks("org_mode_hook"); | |
| message("Org mode (Babel 11+ languages – Go added) loaded. C-c C-c = execute source block."); | |
| } | |
| % =================================================================== | |
| % Auto-activation | |
| % =================================================================== | |
| add_mode_for_extension("org", "org"); | |
| add_mode_for_extension("org", "org_archive"); | |
| static define org_mode_if_org_file() | |
| { | |
| if (buffer_filename() matches "\\.org$") | |
| org_mode(); | |
| } | |
| add_to_hook("find_file_hook", &org_mode_if_org_file); | |
| % =================================================================== | |
| % Ready for even more languages (just add another case in the switch). | |
| % Go support is now live – enjoy full Org + Babel power inside Jed! |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a primitive attempt at vibe coding an Org-mode extension for the Jed Text Editor.
I wanted to see what was possible using AI for coding.