[PATCH] Minimal org-mode support
François Revol <[email protected]> Mon, 06 Jan 2014 13:02:09 +0100
| Newsgroups | gmane.editors.qemacs.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi, I got bored yesterday evening, so I wrote a minimal org-mode support. For now it supports: - bullet lists highlight - TODO/DONE/ highlight and cycling - bullet line and subtree promotion/demotion However I couldn't get the correct bindings for those yet so I took arbitrary keys for now. I don't intend to make a full org-mode clone, as it's way too complex, and it's much less useful without folding support, but for note taking and TODO list it might be useful enough. cf. http://orgmode.org/ François. _______________________________________________ Qemacs-devel mailing list [email protected] https://lists.nongnu.org/mailman/listinfo/qemacs-devel
qemacs-org-mode-001.diff
(text/x-patch, 9.7 KB)
Index: Makefile
===================================================================
RCS file: /sources/qemacs/qemacs/Makefile,v
retrieving revision 1.57
diff -u -r1.57 Makefile
--- Makefile 2 Jan 2014 10:10:24 -0000 1.57
+++ Makefile 6 Jan 2014 11:56:10 -0000
@@ -111,7 +111,7 @@
ifdef CONFIG_ALL_MODES
OBJS+= unihex.o clang.o xml.o bufed.o \
- lisp.o makemode.o perl.o htmlsrc.o script.o variables.o
+ lisp.o makemode.o org-mode.o perl.o htmlsrc.o script.o variables.o
ifndef CONFIG_WIN32
OBJS+= shell.o dired.o latex-mode.o
endif
--- /dev/null 2013-11-11 13:26:50.667131979 +0100
+++ org-mode.c 2014-01-06 12:54:48.000000000 +0100
@@ -0,0 +1,362 @@
+/*
+ * Org mode for QEmacs.
+ *
+ * Copyright (c) 2001, 2002 Fabrice Bellard.
+ * Copyright (c) 2002-2013 Charlie Gordon.
+ * Copyright (c) 2014 Francois Revol.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "qe.h"
+
+ModeDef org_mode;
+
+#define IN_BULLET 0x01
+#define IN_ACTION 0x02
+#define IN_TAG 0x04
+
+#define MAX_BUF_SIZE 512
+
+
+/* TODO: define specific styles */
+static struct OrgTodoKeywords {
+ const char *keyword;
+ int style;
+} OrgTodoKeywords [] = {
+ {"TODO", QE_STYLE_STRING},
+ {"DONE", QE_STYLE_TYPE}
+};
+
+/* TODO: define specific styles */
+#define BULLET_STYLES 5
+static int OrgBulletStyles[BULLET_STYLES] = {
+ QE_STYLE_FUNCTION,
+ QE_STYLE_VARIABLE,
+ QE_STYLE_PREPROCESS,
+ QE_STYLE_STRING,
+ QE_STYLE_TYPE
+};
+
+static int org_bullet_depth(int *str, int n)
+{
+ int i;
+
+ for (i = 0; i < n && (str[i] & CHAR_MASK) == '*'; i++) {
+ if ((str[i + 1] & CHAR_MASK) == ' ') {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static int org_todo_keyword(int *str, int n)
+{
+ int i;
+ char c;
+ int klen;
+ char kbuf[32];
+
+ klen = 0;
+ for (i = 0; i < n && qe_isalpha(c = (str[i] & CHAR_MASK)); i++) {
+ if (klen < countof(kbuf) - 1)
+ kbuf[klen++] = c;
+ else
+ break;
+ }
+ kbuf[klen] = '\0';
+ if (klen > 0 && c == ' ') {
+ int k;
+ for (k = 0; k < countof(OrgTodoKeywords); k++) {
+ if (!strcmp(kbuf, OrgTodoKeywords[k].keyword)) {
+ set_color(str, str + i, OrgTodoKeywords[k].style);
+ return k;
+ }
+ }
+ }
+ return -1;
+}
+
+static void org_colorize_line(unsigned int *str, int n, int *statep,
+ __unused__ int state_only)
+{
+ int colstate = *statep;
+ int bullets = 0;
+ int base_style = 0;
+ int i = 0, j = 0;
+ int klen;
+ char kbuf[32];
+ char c;
+ int k;
+
+ bullets = org_bullet_depth(str, n);
+ if (bullets > -1) {
+ colstate = IN_BULLET;
+ base_style = OrgBulletStyles[bullets % BULLET_STYLES];
+ set_color(str, str + bullets + 1, base_style);
+ i = bullets + 2;
+ }
+
+ if (colstate & IN_BULLET) {
+ int kw = org_todo_keyword(str + i, n - i);
+ if (kw > -1) {
+ int kwlen = strlen(OrgTodoKeywords[kw].keyword);
+ set_color(str + i, str + i + kwlen, OrgTodoKeywords[kw].style);
+ i += kwlen;
+ }
+ }
+
+ while (i < n) {
+ c = str[i] & CHAR_MASK;
+ switch (c) {
+ default:
+ break;
+ }
+ set_color1(str + i, base_style);
+ i++;
+ continue;
+ }
+
+ colstate = 0;
+ *statep = colstate;
+}
+
+static void do_org_todo(EditState *s)
+{
+ int offset, offsetl, line_num, col_num, bullets, len;
+ unsigned int buf[MAX_BUF_SIZE], *p;
+ int kw;
+
+ /* find start of line */
+ eb_get_pos(s->b, &line_num, &col_num, s->offset);
+ offset = eb_goto_bol(s->b, s->offset);
+ do {
+ offsetl = offset;
+ len = eb_get_line(s->b, buf, countof(buf), &offsetl);
+ bullets = org_bullet_depth(buf, len);
+ if (bullets > -1) {
+ break;
+ }
+ offsetl = offset;
+ offset = eb_prev_line(s->b, offset);
+ } while (offsetl > 0);
+
+ if (bullets < 0)
+ return;
+
+ offset = eb_goto_bol(s->b, offset);
+ kw = org_todo_keyword(buf + bullets + 2, len - bullets);
+
+ if (kw > -1) {
+ int kwlen = strlen(OrgTodoKeywords[kw].keyword);
+ eb_delete(s->b, offset + bullets + 2, kwlen + 1);
+ }
+
+ kw++;
+
+ if (kw < countof(OrgTodoKeywords)) {
+ int kwlen = strlen(OrgTodoKeywords[kw].keyword);
+ eb_insert(s->b, offset + bullets + 2, " ", 1);
+ eb_insert(s->b, offset + bullets + 2, OrgTodoKeywords[kw].keyword, kwlen);
+ }
+}
+
+static void do_org_meta_return(EditState *s)
+{
+ int offset, offsetl, line_num, col_num, bullets, len;
+ unsigned int buf[MAX_BUF_SIZE], *p;
+ int kw;
+
+ /* find start of line */
+ eb_get_pos(s->b, &line_num, &col_num, s->offset);
+ offset = eb_goto_bol(s->b, s->offset);
+ offsetl = offset;
+ len = eb_get_line(s->b, buf, countof(buf), &offsetl);
+ bullets = org_bullet_depth(buf, len);
+ if (bullets < 0)
+ return;
+
+ if (col_num > 0)
+ offset = offsetl;
+
+ eb_insert(s->b, offset, " \n", 2);
+ do {
+ eb_insert(s->b, offset, "*", 1);
+ } while (bullets--);
+ eb_goto_eol(s->b, offset);
+ if (col_num > 0)
+ text_move_up_down(s, 1);
+ text_move_eol(s);
+}
+
+static void do_org_insert_todo_heading(EditState *s)
+{
+ printf("M-S-RET\n");
+ /* TODO */
+}
+
+static void do_org_promote(EditState *s, int dir)
+{
+ int offset, offsetl, line_num, col_num, len;
+ int bullets;
+ unsigned int buf[MAX_BUF_SIZE], *p;
+ int kw;
+
+ /* find start of line */
+ eb_get_pos(s->b, &line_num, &col_num, s->offset);
+ offset = eb_goto_bol(s->b, s->offset);
+ offsetl = offset;
+ len = eb_get_line(s->b, buf, countof(buf), &offsetl);
+ bullets = org_bullet_depth(buf, len);
+ if (bullets < 0)
+ return;
+
+ if (dir > 0)
+ eb_insert(s->b, offset, "*", 1);
+ if (dir < 0 && bullets > 0)
+ eb_delete(s->b, offset, 1);
+}
+
+static void do_org_promote_subtree(EditState *s, int dir)
+{
+ int offset, offsetl, offseti, line_num, col_num, len;
+ int bullets, bullets1;
+ unsigned int buf[MAX_BUF_SIZE], *p;
+ int kw;
+
+ /* find start of line */
+ eb_get_pos(s->b, &line_num, &col_num, s->offset);
+ offset = eb_goto_bol(s->b, s->offset);
+ offsetl = offset;
+ len = eb_get_line(s->b, buf, countof(buf), &offsetl);
+ bullets = org_bullet_depth(buf, len);
+ if (bullets < 0)
+ return;
+
+ if (dir > 0)
+ eb_insert(s->b, offset, "*", 1);
+ else if (dir < 0 && bullets > 0)
+ eb_delete(s->b, offset, 1);
+ else
+ return;
+
+ bullets1 = bullets;
+ for (;;) {
+ offsetl = eb_next_line(s->b, offset);
+ if (offsetl == offset)
+ break;
+ offset = offseti = offsetl;
+ eb_get_pos(s->b, &line_num, &col_num, offseti);
+ len = eb_get_line(s->b, buf, countof(buf), &offseti);
+ bullets = org_bullet_depth(buf, len);
+ if (bullets < 0)
+ continue;
+ if (bullets <= bullets1)
+ break;
+
+ if (dir > 0)
+ eb_insert(s->b, offset, "*", 1);
+ if (dir < 0 && bullets > 0)
+ eb_delete(s->b, offset, 1);
+ }
+}
+
+static void do_org_metaleft(EditState *s)
+{
+ do_org_promote(s, -1);
+}
+
+static void do_org_metaright(EditState *s)
+{
+ do_org_promote(s, 1);
+}
+
+static void do_org_shiftmetaleft(EditState *s)
+{
+ do_org_promote_subtree(s, -1);
+}
+
+static void do_org_shiftmetaright(EditState *s)
+{
+ do_org_promote_subtree(s, 1);
+}
+
+static int org_mode_probe(ModeDef *mode, ModeProbeData *p)
+{
+ /* just check file extension */
+ if (match_extension(p->filename, mode->extensions))
+ return 80;
+
+ return 0;
+}
+
+static int org_mode_init(EditState *s, __unused__ ModeSavedData *saved_data)
+{
+ int ret;
+
+ ret = text_mode_init(s, saved_data);
+ if (ret)
+ return ret;
+
+ s->wrap = WRAP_TRUNCATE;
+ return 0;
+}
+
+static void org_mode_close(__unused__ EditState *s)
+{
+}
+
+/* Org mode specific commands */
+static CmdDef org_commands[] = {
+ /* actually C-c C-t */
+ CMD2( KEY_CTRL('t'), KEY_NONE,
+ "org-todo", do_org_todo, ES, "*")
+ CMD2( KEY_META(KEY_RET), KEY_NONE,
+ "org-meta-return", do_org_meta_return, ES, "*")
+ /*
+ CMD2( KEY_META_S('\n'), KEY_NONE,
+ "org-insert-todo-heading", do_org_insert_todo_heading, ES, "*")
+ */
+ /* actually M-left */
+ CMD2( KEY_CTRL_LEFT, KEY_NONE,
+ "org-metaleft", do_org_metaleft, ES, "*")
+ /* actually M-right */
+ CMD2( KEY_CTRL_RIGHT, KEY_NONE,
+ "org-metaright", do_org_metaright, ES, "*")
+ /* actually M-S-left */
+ CMD2( KEY_CTRLX('<'), KEY_NONE,
+ "org-shiftmetaleft", do_org_shiftmetaleft, ES, "*")
+ /* actually M-S-right */
+ CMD2( KEY_CTRLX('>'), KEY_NONE,
+ "org-shiftmetaright", do_org_shiftmetaright, ES, "*")
+ CMD_DEF_END,
+};
+
+static int org_init(void)
+{
+ memcpy(&org_mode, &text_mode, sizeof(ModeDef));
+ org_mode.name = "org";
+ org_mode.extensions = "org";
+ org_mode.mode_probe = org_mode_probe;
+ org_mode.colorize_func = org_colorize_line;
+ org_mode.mode_init = org_mode_init;
+
+ qe_register_mode(&org_mode);
+ qe_register_cmd_table(org_commands, &org_mode);
+
+ return 0;
+}
+
+qe_module_init(org_init);