qemacs-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemacs-commit] qemacs bufed.c dired.c extras.c list.c makemode...


From: Charlie Gordon
Subject: [Qemacs-commit] qemacs bufed.c dired.c extras.c list.c makemode...
Date: Mon, 10 Feb 2014 21:21:41 +0000

CVSROOT:        /sources/qemacs
Module name:    qemacs
Changes by:     Charlie Gordon <chqrlie>        14/02/10 21:21:40

Modified files:
        .              : bufed.c dired.c extras.c list.c makemode.c qe.c 
                         qe.h qeconfig.h shell.c 

Log message:
        Improve mode selection and mode specific command safety
        
        * add set-auto-mode() to (re)select best mode for buffer
        * add set-next-mode() on M-m to cycle appropriate buffer modes
        * add set-previous-mode()
        * add default_mode and saved_mode in buffers to improve mode switching
        * add dired mode probing and store st_mode in buffer to detect 
directories
        * add charset, eol_type and buffer in ModeProbeData
        * clean mode selection and window buffer attachment (needs more work)
        * compute sorted list of appropriate modes in probe_mode
        * convert charset and eol_type in mode_probe
        * add signatures in buffer priv_data to perform save casts
        * move BufedState to b->priv_data, protect mode specific functions
          add bufed_mode_probe function, cycling through modes comes back to 
bufed mode
        * move DiredState to b->priv_data, protect mode specific functions
          add dired_mode_probe function, cycling through modes comes back to 
dired mode
        * add heading line in dired buffer with directory spec
        * protect shell-mode specific functions.
        * restart shell in shell() command if exited
        * some cosmetics changes (remove useless __unused__, missing messages 
...)

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/qemacs/bufed.c?cvsroot=qemacs&r1=1.24&r2=1.25
http://cvs.savannah.gnu.org/viewcvs/qemacs/dired.c?cvsroot=qemacs&r1=1.36&r2=1.37
http://cvs.savannah.gnu.org/viewcvs/qemacs/extras.c?cvsroot=qemacs&r1=1.20&r2=1.21
http://cvs.savannah.gnu.org/viewcvs/qemacs/list.c?cvsroot=qemacs&r1=1.11&r2=1.12
http://cvs.savannah.gnu.org/viewcvs/qemacs/makemode.c?cvsroot=qemacs&r1=1.9&r2=1.10
http://cvs.savannah.gnu.org/viewcvs/qemacs/qe.c?cvsroot=qemacs&r1=1.149&r2=1.150
http://cvs.savannah.gnu.org/viewcvs/qemacs/qe.h?cvsroot=qemacs&r1=1.140&r2=1.141
http://cvs.savannah.gnu.org/viewcvs/qemacs/qeconfig.h?cvsroot=qemacs&r1=1.46&r2=1.47
http://cvs.savannah.gnu.org/viewcvs/qemacs/shell.c?cvsroot=qemacs&r1=1.84&r2=1.85

Patches:
Index: bufed.c
===================================================================
RCS file: /sources/qemacs/qemacs/bufed.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -b -r1.24 -r1.25
--- bufed.c     15 Jan 2014 19:44:24 -0000      1.24
+++ bufed.c     10 Feb 2014 21:21:39 -0000      1.25
@@ -25,7 +25,10 @@
     BUFED_ALL_VISIBLE = 1
 };
 
+static int bufed_signature;
+
 typedef struct BufedState {
+    void *signature;
     StringArray items;
     int flags;
     int last_index;
@@ -33,32 +36,47 @@
 
 static ModeDef bufed_mode;
 
+static BufedState *bufed_get_state(EditState *s)
+{
+    BufedState *bs = s->b->priv_data;
+
+    if (bs && bs->signature == &bufed_signature)
+        return bs;
+
+    put_status(s, "Not a bufed buffer");
+    return NULL;
+}
+
 static void build_bufed_list(EditState *s)
 {
     QEmacsState *qs = s->qe_state;
     EditBuffer *b;
-    BufedState *hs;
+    BufedState *bs;
     int last_index = list_get_pos(s);
-    int i, flags;
+    int i;
 
-    hs = s->mode_data;
+    if (!(bs = bufed_get_state(s)))
+        return;
 
-    free_strings(&hs->items);
+    free_strings(&bs->items);
     for (b = qs->first_buffer; b != NULL; b = b->next) {
-        if (!(b->flags & BF_SYSTEM) || (hs->flags & BUFED_ALL_VISIBLE))
-            add_string(&hs->items, b->name);
+        if (!(b->flags & BF_SYSTEM) || (bs->flags & BUFED_ALL_VISIBLE))
+            add_string(&bs->items, b->name);
     }
 
     /* build buffer */
     b = s->b;
-    flags = b->flags;
     b->flags &= ~BF_READONLY;
     eb_delete(b, 0, b->total_size);
-    for (i = 0; i < hs->items.nb_items; i++) {
-        EditBuffer *b1 = eb_find(hs->items.items[i]->str);
+
+    for (i = 0; i < bs->items.nb_items; i++) {
+        EditBuffer *b1 = eb_find(bs->items.items[i]->str);
         char flags[4];
         char *flagp = flags;
 
+        if (i == last_index) {
+            s->offset = b->total_size;
+        }
         if (b1) {
             if (b1->modified)
                 *flagp++ = '*';
@@ -66,14 +84,20 @@
                 *flagp++ = '%';
         }
         *flagp = '\0';
-        eb_printf(b, " %-2s%-16s", flags, hs->items.items[i]->str);
+        eb_printf(b, " %-2s%-16s", flags, bs->items.items[i]->str);
         if (b1) {
             char path[MAX_FILENAME_SIZE];
             const char *mode_name;
             EditState *e;
 
+            if (b1->saved_mode) {
+                mode_name = b1->saved_mode->name;
+            } else
             if (b1->saved_data) {
                 mode_name = b1->saved_data->mode->name;
+            } else
+            if (b1->default_mode) {
+                mode_name = b1->default_mode->name;
             } else {
                 mode_name = "none";
                 for (e = qs->first_window; e != NULL; e = e->next_window) {
@@ -93,15 +117,18 @@
         }
         eb_printf(b, "\n");
     }
-    b->flags = flags;
-    s->offset = eb_goto_pos(s->b, last_index, 0);
+    b->modified = 0;
+    b->flags |= BF_READONLY;
 }
 
 static EditBuffer *bufed_get_buffer(EditState *s)
 {
-    BufedState *bs = s->mode_data;
+    BufedState *bs;
     int index;
 
+    if (!(bs = bufed_get_state(s)))
+        return NULL;
+
     index = list_get_pos(s);
     if (index < 0 || index >= bs->items.nb_items)
         return NULL;
@@ -111,12 +138,15 @@
 
 static void bufed_select(EditState *s, int temp)
 {
-    BufedState *bs = s->mode_data;
+    BufedState *bs;
     StringItem *item;
     EditBuffer *b;
     EditState *e;
     int index;
 
+    if (!(bs = bufed_get_state(s)))
+        return;
+
     index = list_get_pos(s);
     if (index < 0 || index >= bs->items.nb_items)
         return;
@@ -137,7 +167,7 @@
         return;
     }
     if (e) {
-        /* delete dired window */
+        /* delete bufed window */
         do_delete_window(s, 1);
         switch_to_buffer(e, b);
     } else {
@@ -175,13 +205,20 @@
 static void bufed_kill_item(void *opaque, StringItem *item)
 {
     EditState *s = opaque;
+
+    /* XXX: avoid killing buffer list by mistake */
+    if (strcmp(s->b->name, item->str))
     do_kill_buffer(s, item->str);
 }
 
 static void bufed_kill_buffer(EditState *s)
 {
-    BufedState *hs = s->mode_data;
-    string_selection_iterate(&hs->items, list_get_pos(s),
+    BufedState *bs;
+
+    if (!(bs = bufed_get_state(s)))
+        return;
+
+    string_selection_iterate(&bs->items, list_get_pos(s),
                              bufed_kill_item, s);
     build_bufed_list(s);
 }
@@ -209,7 +246,9 @@
     e = insert_window_left(b, width, WF_MODELINE);
     edit_set_mode(e, &bufed_mode);
 
-    bs = e->mode_data;
+    if (!(bs = bufed_get_state(e)))
+        return;
+
     if (argval != NO_ARG) {
         bs->flags |= BUFED_ALL_VISIBLE;
         build_bufed_list(e);
@@ -257,7 +296,10 @@
 
 static void bufed_refresh(EditState *s, int toggle)
 {
-    BufedState *bs = s->mode_data;
+    BufedState *bs;
+
+    if (!(bs = bufed_get_state(s)))
+        return;
 
     if (toggle)
         bs->flags ^= BUFED_ALL_VISIBLE;
@@ -274,21 +316,57 @@
     bufed_select(s, 1);
 }
 
+static int bufed_mode_probe(ModeDef *mode, ModeProbeData *p)
+{
+    if (p->b->priv_data) {
+        BufedState *bs = p->b->priv_data;
+        if (bs->signature == &bufed_signature)
+            return 95;
+        else
+            return 0;
+    }
+    return 0;
+}
+
+static void bufed_close(EditBuffer *b)
+{
+    BufedState *bs = b->priv_data;
+
+    if (bs) {
+        free_strings(&bs->items);
+    }
+
+    qe_free(&b->priv_data);
+}
+
 static int bufed_mode_init(EditState *s, ModeSavedData *saved_data)
 {
+    BufedState *bs;
+
     list_mode.mode_init(s, saved_data);
 
-    build_bufed_list(s);
+    if (s->b->priv_data) {
+        bs = s->b->priv_data;
+        if (bs->signature != &bufed_signature)
+            return -1;
+    } else {
+        /* XXX: should be allocated by buffer_load API */
+        bs = qe_mallocz(BufedState);
+        if (!bs)
+            return -1;
+
+        bs->signature = &bufed_signature;
+        s->b->priv_data = bs;
+        s->b->close = bufed_close;
 
+        /* XXX: should be built by buffer_load API */
+        build_bufed_list(s);
+    }
     return 0;
 }
 
 static void bufed_mode_close(EditState *s)
 {
-    BufedState *bs = s->mode_data;
-
-    free_strings(&bs->items);
-
     list_mode.mode_close(s);
 }
 
@@ -315,7 +393,7 @@
           "previous-line", do_up_down, -1)
     CMD1( 'r', 'g',
           "bufed-refresh", bufed_refresh, 0)
-    CMD0( 'k', KEY_F8,
+    CMD0( 'k', 'd',
           "bufed-kill-buffer", bufed_kill_buffer)
     CMD_DEF_END,
 };
@@ -332,7 +410,7 @@
     /* CG: assuming list_mode already initialized ? */
     memcpy(&bufed_mode, &list_mode, sizeof(ModeDef));
     bufed_mode.name = "bufed";
-    bufed_mode.instance_size = sizeof(BufedState);
+    bufed_mode.mode_probe = bufed_mode_probe;
     bufed_mode.mode_init = bufed_mode_init;
     bufed_mode.mode_close = bufed_mode_close;
     /* CG: not a good idea, display hook has side effect on layout */

Index: dired.c
===================================================================
RCS file: /sources/qemacs/qemacs/dired.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -b -r1.36 -r1.37
--- dired.c     5 Feb 2014 00:56:49 -0000       1.36
+++ dired.c     10 Feb 2014 21:21:39 -0000      1.37
@@ -21,7 +21,7 @@
 
 #include "qe.h"
 
-enum { DIRED_HEADER = 0 };
+enum { DIRED_HEADER = 1 };
 
 enum {
     DIRED_SORT_NAME = 1,
@@ -33,7 +33,10 @@
     DIRED_SORT_DESCENDING = 32,
 };
 
+static int dired_signature;
+
 typedef struct DiredState {
+    void *signature;
     StringArray items;
     int sort_mode; /* DIRED_SORT_GROUP | DIRED_SORT_NAME */
     int last_index;
@@ -55,12 +58,11 @@
     return list_get_pos(s) - DIRED_HEADER;
 }
 
-static void dired_free(EditState *s)
+static void dired_free(DiredState *ds)
 {
-    DiredState *ds = s->mode_data;
+    if (ds) {
     int i;
 
-    /* free opaques */
     for (i = 0; i < ds->items.nb_items; i++) {
         qe_free(&ds->items.items[i]->opaque);
     }
@@ -68,44 +70,58 @@
     free_strings(&ds->items);
 
     ds->last_index = -1;
+    }
+}
 
-    /* reset cursor position */
-    s->offset_top = 0;
-    s->offset = 0;
+static DiredState *dired_get_state(EditState *s)
+{
+    DiredState *ds = s->b->priv_data;
+
+    if (ds && ds->signature == &dired_signature)
+        return ds;
+
+    put_status(s, "Not a dired buffer");
+    return NULL;
 }
 
 static char *dired_get_filename(EditState *s,
                                 char *buf, int buf_size, int index)
 {
-    DiredState *hs = s->mode_data;
+    DiredState *ds;
     const StringItem *item;
     const DiredItem *dip;
 
+    if (!(ds = dired_get_state(s)))
+        return NULL;
+
     /* CG: assuming buf_size > 0 */
     buf[0] = '\0';
 
     if (index < 0)
         index = dired_get_index(s);
 
-    if (index < 0 || index >= hs->items.nb_items)
+    if (index < 0 || index >= ds->items.nb_items)
         return NULL;
 
-    item = hs->items.items[index];
+    item = ds->items.items[index];
     dip = item->opaque;
 
     /* build filename */
     /* CG: Should canonicalize path */
-    return makepath(buf, buf_size, hs->path, dip->name);
+    return makepath(buf, buf_size, ds->path, dip->name);
 }
 
 static int dired_find_target(EditState *s, const char *target)
 {
-    DiredState *hs = s->mode_data;
+    DiredState *ds;
     char filename[MAX_FILENAME_SIZE];
     int i;
 
     if (target) {
-        for (i = 0; i < hs->items.nb_items; i++) {
+        if (!(ds = dired_get_state(s)))
+            return -1;
+
+        for (i = 0; i < ds->items.nb_items; i++) {
             if (dired_get_filename(s, filename, sizeof(filename), i)
             &&  strequal(filename, target)) {
                 return i;
@@ -159,34 +175,38 @@
 /* select current item */
 static void dired_sort_list(EditState *s)
 {
-    DiredState *hs = s->mode_data;
+    DiredState *ds;
     StringItem *item, *cur_item;
     DiredItem *dip;
     EditBuffer *b;
     int index, i;
 
+    if (!(ds = dired_get_state(s)))
+        return;
+
     index = dired_get_index(s);
     cur_item = NULL;
-    if (index >= 0 && index < hs->items.nb_items)
-        cur_item = hs->items.items[index];
+    if (index >= 0 && index < ds->items.nb_items)
+        cur_item = ds->items.items[index];
 
-    qsort(hs->items.items, hs->items.nb_items,
+    qsort(ds->items.items, ds->items.nb_items,
           sizeof(StringItem *), dired_sort_func);
 
     /* construct list buffer */
     b = s->b;
     b->flags &= ~BF_READONLY;
     eb_delete(b, 0, b->total_size);
-    s->offset_top = 0;
-    s->offset = 0;
-    if (DIRED_HEADER)
-        eb_printf(b, "  %s:\n", hs->path);
-    for (i = 0; i < hs->items.nb_items; i++) {
-        item = hs->items.items[i];
+
+    if (DIRED_HEADER) {
+        eb_printf(b, "  Directory of %s:\n", ds->path);
+    }
+
+    for (i = 0; i < ds->items.nb_items; i++) {
+        item = ds->items.items[i];
         dip = item->opaque;
         dip->offset = b->total_size;
         if (item == cur_item) {
-            hs->last_index = i;
+            ds->last_index = i;
             s->offset = b->total_size;
         }
         eb_printf(b, "%c %s\n", dip->mark, item->str);
@@ -197,17 +217,19 @@
 
 static void dired_mark(EditState *s, int mark)
 {
-    DiredState *hs = s->mode_data;
+    DiredState *ds;
     const StringItem *item;
     DiredItem *dip;
     unsigned char ch;
     int index;
 
-    index = dired_get_index(s);
+    if (!(ds = dired_get_state(s)))
+        return;
 
-    if (index < 0 || index >= hs->items.nb_items)
+    index = dired_get_index(s);
+    if (index < 0 || index >= ds->items.nb_items)
         return;
-    item = hs->items.items[index];
+    item = ds->items.items[index];
     dip = item->opaque;
 
     ch = dip->mark = mark;
@@ -221,41 +243,44 @@
 
 static void dired_sort(EditState *s, const char *sort_order)
 {
-    DiredState *hs = s->mode_data;
+    DiredState *ds;
     const char *p;
 
+    if (!(ds = dired_get_state(s)))
+        return;
+
     for (p = sort_order; *p; p++) {
         switch (qe_tolower((unsigned char)*p)) {
         case 'n':       /* name */
-            hs->sort_mode &= ~DIRED_SORT_MASK;
-            hs->sort_mode |= DIRED_SORT_NAME;
+            ds->sort_mode &= ~DIRED_SORT_MASK;
+            ds->sort_mode |= DIRED_SORT_NAME;
             break;
         case 'e':       /* extension */
-            hs->sort_mode &= ~DIRED_SORT_MASK;
-            hs->sort_mode |= DIRED_SORT_EXTENSION;
+            ds->sort_mode &= ~DIRED_SORT_MASK;
+            ds->sort_mode |= DIRED_SORT_EXTENSION;
             break;
         case 's':       /* size */
-            hs->sort_mode &= ~DIRED_SORT_MASK;
-            hs->sort_mode |= DIRED_SORT_SIZE;
+            ds->sort_mode &= ~DIRED_SORT_MASK;
+            ds->sort_mode |= DIRED_SORT_SIZE;
             break;
         case 'd':       /* direct */
-            hs->sort_mode &= ~DIRED_SORT_MASK;
-            hs->sort_mode |= DIRED_SORT_DATE;
+            ds->sort_mode &= ~DIRED_SORT_MASK;
+            ds->sort_mode |= DIRED_SORT_DATE;
             break;
         case 'u':       /* ungroup */
-            hs->sort_mode &= ~DIRED_SORT_GROUP;
+            ds->sort_mode &= ~DIRED_SORT_GROUP;
             break;
         case 'g':       /* group */
-            hs->sort_mode |= DIRED_SORT_GROUP;
+            ds->sort_mode |= DIRED_SORT_GROUP;
             break;
         case '+':       /* ascending */
-            hs->sort_mode &= ~DIRED_SORT_DESCENDING;
+            ds->sort_mode &= ~DIRED_SORT_DESCENDING;
             break;
         case '-':       /* descending */
-            hs->sort_mode |= DIRED_SORT_DESCENDING;
+            ds->sort_mode |= DIRED_SORT_DESCENDING;
             break;
         case 'r':       /* reverse */
-            hs->sort_mode ^= DIRED_SORT_DESCENDING;
+            ds->sort_mode ^= DIRED_SORT_DESCENDING;
             break;
         }
     }
@@ -267,7 +292,7 @@
 static void dired_build_list(EditState *s, const char *path,
                              const char *target)
 {
-    DiredState *hs = s->mode_data;
+    DiredState *ds;
     FindFileState *ffst;
     char filename[MAX_FILENAME_SIZE];
     char line[1024], buf[1024];
@@ -276,15 +301,18 @@
     int ct, len, index;
     StringItem *item;
 
+    if (!(ds = dired_get_state(s)))
+        return;
+
     /* free previous list, if any */
-    dired_free(s);
+    dired_free(ds);
 
     /* CG: should make absolute ? */
-    canonicalize_path(hs->path, sizeof(hs->path), path);
-    eb_set_filename(s->b, hs->path);
+    canonicalize_path(ds->path, sizeof(ds->path), path);
+    eb_set_filename(s->b, ds->path);
     s->b->flags |= BF_DIRED;
 
-    ffst = find_file_open(hs->path, "*");
+    ffst = find_file_open(ds->path, "*");
     /* Should scan directory/filespec before computing lines to adjust
      * filename gutter width
      */
@@ -351,13 +379,13 @@
         }
         pstrcat(line, sizeof(line), buf);
 
-        item = add_string(&hs->items, line);
+        item = add_string(&ds->items, line);
         if (item) {
             DiredItem *dip;
             int plen = strlen(p);
 
             dip = qe_malloc_hack(DiredItem, plen);
-            dip->state = hs;
+            dip->state = ds;
             dip->st_mode = st.st_mode;
             dip->size = st.st_size;
             dip->mtime = st.st_mtime;
@@ -371,7 +399,7 @@
     dired_sort_list(s);
 
     index = dired_find_target(s, target);
-    s->offset = eb_goto_pos(s->b, index + DIRED_HEADER, 0);
+    s->offset = eb_goto_pos(s->b, max(index, 0) + DIRED_HEADER, 0);
 }
 
 /* select current item */
@@ -443,31 +471,40 @@
 
 static void dired_parent(EditState *s)
 {
-    DiredState *hs = s->mode_data;
+    DiredState *ds;
     char target[MAX_FILENAME_SIZE];
     char filename[MAX_FILENAME_SIZE];
 
-    pstrcpy(target, sizeof(target), hs->path);
-    makepath(filename, sizeof(filename), hs->path, "..");
+    if (!(ds = dired_get_state(s)))
+        return;
+
+    pstrcpy(target, sizeof(target), ds->path);
+    makepath(filename, sizeof(filename), ds->path, "..");
 
     dired_build_list(s, filename, target);
 }
 
 static void dired_refresh(EditState *s)
 {
-    DiredState *hs = s->mode_data;
+    DiredState *ds;
     char target[MAX_FILENAME_SIZE];
 
+    if (!(ds = dired_get_state(s)))
+        return;
+
     dired_get_filename(s, target, sizeof(target), -1);
-    dired_build_list(s, hs->path, target);
+    dired_build_list(s, ds->path, target);
 }
 
 static void dired_display_hook(EditState *s)
 {
-    DiredState *ds = s->mode_data;
+    DiredState *ds;
     char filename[MAX_FILENAME_SIZE];
     int index;
 
+    if (!(ds = dired_get_state(s)))
+        return;
+
     /* Prevent point from going beyond list */
     if (s->offset && s->offset == s->b->total_size)
         do_up_down(s, -1);
@@ -486,34 +523,67 @@
     }
 }
 
+static void dired_close(EditBuffer *b)
+{
+    DiredState *ds = b->priv_data;
+
+    dired_free(ds);
+    qe_free(&b->priv_data);
+}
+
 static int dired_mode_init(EditState *s, ModeSavedData *saved_data)
 {
-    DiredState *hs;
+    DiredState *ds;
 
     list_mode.mode_init(s, saved_data);
 
-    /* XXX: File system charset should be detected automatically */
-    eb_set_charset(s->b, &charset_utf8, s->b->eol_type);
+    if (s->b->priv_data) {
+        ds = s->b->priv_data;
+        if (ds->signature != &dired_signature)
+            return -1;
+    } else {
+        /* XXX: should be allocated by buffer_load API */
+        ds = qe_mallocz(DiredState);
+        if (!ds)
+            return -1;
 
-    hs = s->mode_data;
-    hs->sort_mode = DIRED_SORT_GROUP | DIRED_SORT_NAME;
+        ds->signature = &dired_signature;
+        ds->sort_mode = DIRED_SORT_GROUP | DIRED_SORT_NAME;
 
+        s->b->priv_data = ds;
+        s->b->close = dired_close;
+
+        /* XXX: should be built by buffer_load API */
     dired_build_list(s, s->b->filename, NULL);
+    }
+
+    /* XXX: File system charset should be detected automatically */
+    /* XXX: If file system charset is not utf8, eb_printf will fail */
+    eb_set_charset(s->b, &charset_utf8, s->b->eol_type);
 
     return 0;
 }
 
 static void dired_mode_close(EditState *s)
 {
-    dired_free(s);
     list_mode.mode_close(s);
 }
 
 /* can only apply dired mode on directories */
 static int dired_mode_probe(ModeDef *mode, ModeProbeData *p)
 {
-    if (S_ISDIR(p->st_mode))
+    if (p->b->priv_data) {
+        DiredState *ds = p->b->priv_data;
+        if (ds->signature != &dired_signature)
+            return 0;
+        else
         return 100;
+    }
+    if (S_ISDIR(p->st_mode))
+        return 95;
+    else
+    if (strchr(p->real_filename, '*') || strchr(p->real_filename, '?'))
+        return 90;
     else
         return 0;
 }
@@ -557,7 +627,7 @@
     edit_set_mode(e, &dired_mode);
 
     index = dired_find_target(e, target);
-    e->offset = eb_goto_pos(e->b, index + DIRED_HEADER, 0);
+    e->offset = eb_goto_pos(e->b, max(index, 0) + DIRED_HEADER, 0);
 
     /* modify active window */
     qs->active_window = e;
@@ -621,7 +691,6 @@
     /* CG: assuming list_mode already initialized ? */
     memcpy(&dired_mode, &list_mode, sizeof(ModeDef));
     dired_mode.name = "dired";
-    dired_mode.instance_size = sizeof(DiredState);
     dired_mode.mode_probe = dired_mode_probe;
     dired_mode.mode_init = dired_mode_init;
     dired_mode.mode_close = dired_mode_close;

Index: extras.c
===================================================================
RCS file: /sources/qemacs/qemacs/extras.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -b -r1.20 -r1.21
--- extras.c    10 Feb 2014 20:33:01 -0000      1.20
+++ extras.c    10 Feb 2014 21:21:40 -0000      1.21
@@ -764,6 +764,9 @@
     eb_printf(b1, "    eol_type: %d %s\n", b->eol_type, buf);
     eb_printf(b1, "     charset: %s (bytes=%d, shift=%d)\n",
               b->charset->name, b->char_bytes, b->char_shift);
+    eb_printf(b1, "default_mode: %s, saved_mode: %s\n",
+              b->default_mode ? b->default_mode->name : "",
+              b->saved_mode ? b->saved_mode->name : "");
 
     desc = buf_init(&descbuf, buf, countof(buf));
     if (b->flags & BF_SAVELOG)

Index: list.c
===================================================================
RCS file: /sources/qemacs/qemacs/list.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -b -r1.11 -r1.12
--- list.c      15 Jan 2014 15:54:27 -0000      1.11
+++ list.c      10 Feb 2014 21:21:40 -0000      1.12
@@ -79,7 +79,7 @@
     text_move_up_down(s, 1);
 }
 
-static int list_mode_init(EditState *s, __unused__ ModeSavedData *saved_data)
+static int list_mode_init(EditState *s, ModeSavedData *saved_data)
 {
     text_mode_init(s, saved_data);
 

Index: makemode.c
===================================================================
RCS file: /sources/qemacs/qemacs/makemode.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- makemode.c  6 Feb 2014 00:22:18 -0000       1.9
+++ makemode.c  10 Feb 2014 21:21:40 -0000      1.10
@@ -161,7 +161,7 @@
 
 static ModeDef makefile_mode;
 
-static int makefile_mode_init(EditState *s, __unused__ ModeSavedData 
*saved_data)
+static int makefile_mode_init(EditState *s, ModeSavedData *saved_data)
 {
     text_mode_init(s, saved_data);
     s->b->tab_width = 8;

Index: qe.c
===================================================================
RCS file: /sources/qemacs/qemacs/qe.c,v
retrieving revision 1.149
retrieving revision 1.150
diff -u -b -r1.149 -r1.150
--- qe.c        10 Feb 2014 20:29:26 -0000      1.149
+++ qe.c        10 Feb 2014 21:21:40 -0000      1.150
@@ -1543,6 +1543,8 @@
         eb_delete(s->b, p1, len);
         s->offset = p1;
         qs->this_cmd_func = (CmdFunc)do_append_next_kill;
+    } else {
+        put_status(s, "Region copied");
     }
     selection_activate(qs->screen);
 }
@@ -1729,6 +1731,8 @@
                 b->data_type->buffer_close(b);
                 b->data = NULL;
                 b->data_type = &raw_data_type;
+                eb_delete(b, 0, b->total_size);
+                b->modified = 0;
             }
         }
     }
@@ -1790,6 +1794,7 @@
 {
     ModeDef *m;
 
+    /* XXX: should check if mode is appropriate */
     m = find_mode(name);
     if (m)
         edit_set_mode(s, m);
@@ -1797,51 +1802,6 @@
         put_status(s, "No mode %s", name);
 }
 
-/* CG: should have commands to cycle modes and charsets */
-#if 0
-/* cycle modes appropriate for buffer */
-void do_next_mode(EditState *s)
-{
-    QEmacsState *qs = s->qe_state;
-    char fname[MAX_FILENAME_SIZE];
-    u8 buf[1024];
-    ModeProbeData probe_data;
-    int size;
-    ModeDef *m, *m0;
-
-    size = eb_read(s->b, 0, buf, sizeof(buf));
-    probe_data.buf = buf;
-    probe_data.buf_size = size;
-    probe_data.real_filename = s->b->filename;
-    probe_data.total_size = s->b->total_size;
-    probe_data.st_mode = 0644;
-    probe_data.filename = reduce_filename(fname, sizeof(fname),
-                                          get_basename(s->b->filename));
-    /* CG: should pass EditState? QEmacsState ? */
-
-    /* Should cycle modes in order of decreasing scores */
-    m = m0 = s->mode;
-    for (;;) {
-        m = m->next;
-        if (!m)
-            m = qs->first_mode;
-        if (m == m0)
-            break;
-        if (!m->mode_probe
-        ||  m->mode_probe(m, &probe_data) > 0) {
-            edit_set_mode(s, m);
-            break;
-        }
-    }
-}
-
-void do_cycle_charset(EditState *s)
-{
-    if (++s->b->charset == CHARSET_NB)
-        s->b->charset = 0;
-}
-#endif
-
 QECharset *read_charset(EditState *s, const char *charset_str,
                         EOLType *eol_typep)
 {
@@ -4669,13 +4629,16 @@
     QEmacsState *qs = s->qe_state;
     EditBuffer *b1;
     EditState *e;
-    ModeSavedData *saved_data, **psaved_data;
+    ModeSavedData *saved_data;
     int saved_data_allocated = 0;
     ModeDef *mode;
 
     /* remove region hilite */
     s->region_style = 0;
 
+    if (s->b == b)
+        return;
+
     b1 = s->b;
     if (b1) {
         /* save mode data if no other window uses the buffer */
@@ -4692,10 +4655,10 @@
             /* if no more window uses the buffer:
              * - if transient contents, free the buffer
              * - otherwise, save the mode data in the buffer.
-             *   CG: Should free previous such data ?
              */
             if (!(b1->flags & BF_TRANSIENT)) {
                 qe_free(&b1->saved_data);
+                b1->saved_mode = s->mode;
                 b1->saved_data = s->mode->mode_save_data(s);
             }
         }
@@ -4717,18 +4680,18 @@
                 break;
         }
         if (e) {
-            psaved_data = NULL;
+            mode = e->mode;
             saved_data = e->mode->mode_save_data(e);
             saved_data_allocated = 1;
         } else {
-            psaved_data = &b->saved_data;
-            saved_data = *psaved_data;
+            mode = b->saved_mode;
+            saved_data = b->saved_data;
         }
 
         /* find the mode */
-        if (saved_data)
-            mode = saved_data->mode;
-        else
+        if (!mode)
+            mode = b->default_mode;
+        if (!mode)
             mode = &text_mode; /* default mode */
 
         /* open it ! */
@@ -5070,13 +5033,12 @@
                buffer */
             if (!completion_popup_window) {
                 b = eb_new("*completion*", BF_SYSTEM | BF_UTF8 | BF_TRANSIENT);
+                b->default_mode = &list_mode;
                 w1 = qs->screen->width;
                 h1 = qs->screen->height - qs->status_height;
                 w = (w1 * 3) / 4;
                 h = (h1 * 3) / 4;
                 e = edit_new(b, (w1 - w) / 2, (h1 - h) / 2, w, h, WF_POPUP);
-                /* set list mode */
-                edit_set_mode(e, &list_mode);
                 do_refresh(e);
                 completion_popup_window = e;
             }
@@ -5307,11 +5269,11 @@
     minibuffer_opaque = opaque;
 
     b = eb_new("*minibuf*", BF_SYSTEM | BF_SAVELOG | BF_UTF8);
+    b->default_mode = &minibuffer_mode;
 
     s = edit_new(b, 0, qs->screen->height - qs->status_height,
                  qs->screen->width, qs->status_height, 0);
     /* Should insert at end of window list */
-    edit_set_mode(s, &minibuffer_mode);
     s->prompt = qe_strdup(prompt);
     s->minibuf = 1;
     s->bidir = 0;
@@ -5343,6 +5305,7 @@
     /* minibuf mode inherits from text mode */
     memcpy(&minibuffer_mode, &text_mode, sizeof(ModeDef));
     minibuffer_mode.name = "minibuffer";
+    minibuffer_mode.mode_probe = NULL;
     minibuffer_mode.scroll_up_down = minibuf_complete_scroll_up_down;
     qe_register_mode(&minibuffer_mode);
     qe_register_cmd_table(minibuffer_commands, &minibuffer_mode);
@@ -5416,6 +5379,7 @@
     /* less mode inherits from text mode */
     memcpy(&less_mode, &text_mode, sizeof(ModeDef));
     less_mode.name = "less";
+    less_mode.mode_probe = NULL;
     qe_register_mode(&less_mode);
     qe_register_cmd_table(less_commands, &less_mode);
 }
@@ -5621,24 +5585,31 @@
     splitpath(buf, buf_size, NULL, 0, buf1);
 }
 
-static ModeDef *probe_mode(EditState *s,
+static int probe_mode(EditState *s, EditBuffer *b,
+                      ModeDef **modes, int nb_modes,
+                      int *scores, int min_score,
                            const char *filename, int st_mode, long total_size,
-                           const uint8_t *buf, int len)
+                      const uint8_t *rawbuf, int len,
+                      QECharset *charset, EOLType eol_type)
 {
+    u8 buf[4097];
     QEmacsState *qs = s->qe_state;
     char fname[MAX_FILENAME_SIZE];
-    ModeDef *m, *selected_mode;
+    ModeDef *m;
     ModeProbeData probe_data;
-    int best_probe_score, score;
+    int found_modes;
     const uint8_t *p;
 
-    selected_mode = NULL;
-    best_probe_score = 0;
+    if (!modes || !scores || nb_modes < 1)
+        return 0;
+
+    found_modes = 0;
+    *modes = NULL;
+    *scores = 0;
 
+    probe_data.b = b;
     probe_data.buf = buf;
     probe_data.buf_size = len;
-    p = memchr(buf, '\n', len);
-    probe_data.line_len = p ? p - buf : len;
     probe_data.real_filename = filename;
     probe_data.st_mode = st_mode;
     probe_data.total_size = total_size;
@@ -5646,18 +5617,101 @@
                                           get_basename(filename));
     /* CG: should pass EditState? QEmacsState ? */
 
-    m = qs->first_mode;
-    while (m != NULL) {
+    /* XXX: Should use eb_get_range_contents to deal with charset and
+     * eol_type instead of hand coding this conversion */
+    probe_data.eol_type = eol_type;
+    probe_data.charset = charset;
+    charset_decode_init(&probe_data.charset_state, charset, eol_type);
+
+    if (charset == &charset_utf8
+    ||  charset == &charset_raw
+    ||  charset == &charset_8859_1) {
+        probe_data.buf = rawbuf;
+        probe_data.buf_size = len;
+    } else {
+        int offset = 0;
+        u8 *bufp = buf;
+
+        while (offset < len) {
+            int ch = probe_data.charset_state.table[rawbuf[offset]];
+            offset++;
+            if (ch == ESCAPE_CHAR) {
+                probe_data.charset_state.p = rawbuf + offset - 1;
+                ch = 
probe_data.charset_state.decode_func(&probe_data.charset_state);
+                offset = probe_data.charset_state.p - rawbuf;
+            }
+            bufp += utf8_encode((char *)bufp, ch);
+            if (bufp > buf + sizeof(buf) - MAX_CHAR_BYTES - 1)
+                break;
+            probe_data.buf = buf;
+            probe_data.buf_size = bufp - buf;
+        }
+    }
+    charset_decode_close(&probe_data.charset_state);
+
+    p = memchr(probe_data.buf, '\n', probe_data.buf_size);
+    probe_data.line_len = p ? p - probe_data.buf : probe_data.buf_size;
+
+    for (m = qs->first_mode; m != NULL; m = m->next) {
         if (m->mode_probe) {
-            score = m->mode_probe(m, &probe_data);
-            if (score > best_probe_score) {
-                selected_mode = m;
-                best_probe_score = score;
+            int score = m->mode_probe(m, &probe_data);
+            if (score > min_score) {
+                int i;
+                /* sort appropriate modes by insertion in modes array */
+                for (i = 0; i < found_modes; i++) {
+                    if (scores[i] < score)
+                        break;
+                }
+                if (i < nb_modes) {
+                    if (found_modes >= nb_modes)
+                        found_modes = nb_modes - 1;
+                    if (i < found_modes) {
+                        memmove(modes + i + 1, modes + i,
+                                (found_modes - i) * sizeof(*modes));
+                        memmove(scores + i + 1, scores + i,
+                                (found_modes - i) * sizeof(*scores));
+                    }
+                    modes[i] = m;
+                    scores[i] = score;
+                    found_modes++;
+                }
+            }
+        }
+    }
+    return found_modes;
+}
+
+/* Select appropriate mode for buffer:
+ * iff dir == 0, select best mode 
+ * iff dir > 0, select next mode
+ * iff dir < 0, select previous mode
+ */
+void do_set_next_mode(EditState *s, int dir)
+{
+    u8 buf[4097];
+    int size;
+    ModeDef *modes[32];
+    int scores[32];
+    int i, nb, found;
+    EditBuffer *b = s->b;
+
+    size = eb_read(b, 0, buf, sizeof(buf));
+
+    nb = probe_mode(s, b, modes, countof(modes), scores, 2,
+                    b->filename, b->st_mode, b->total_size,
+                    buf, size, b->charset, b->eol_type);
+    found = 0;
+    if (dir && nb > 0) {
+        for (i = 0; i < nb; i++) {
+            if (s->mode == modes[i]) {
+                found = (i + nb + dir) % nb;
+                break;
             }
         }
-        m = m->next;
     }
-    return selected_mode;
+    edit_set_mode(s, modes[found]);
+    put_status(s, "Mode is now %s, score=%d",
+               modes[found]->name, scores[found]);
 }
 
 /* Should take bits from enumeration instead of booleans */
@@ -5668,10 +5722,13 @@
     char filename[MAX_FILENAME_SIZE];
     int st_mode, buf_size;
     ModeDef *selected_mode;
+    int mode_score;
     EditBuffer *b;
     EditBufferDataType *bdt;
     FILE *f;
     struct stat st;
+    EOLType eol_type = EOL_UNIX;
+    QECharset *charset = &charset_utf8;
 
     if (load_resource) {
         if (find_resource_file(filename, sizeof(filename), filename1)) {
@@ -5713,31 +5770,34 @@
     b = eb_new("", BF_SAVELOG);
     eb_set_filename(b, filename);
 
-    /* Switch to the newly created buffer */
-    switch_to_buffer(s, b);
-
     s->offset = 0;
-    /* CG: need a default setting for this */
-    s->wrap = WRAP_LINE;
+    /* XXX: Should test for full width and WRAP_TRUNCATE if not */
+    s->wrap = WRAP_LINE;        /* default mode may override this */
 
     /* First we try to read the first block to determine the data type */
     if (stat(filename, &st) < 0) {
         /* XXX: default charset should be selectable.  Use utf8 for now */
         eb_set_charset(b, &charset_utf8, b->eol_type);
-        /* CG: should check for wildcards and do dired */
-        //if (strchr(filename, '*') || strchr(filename, '?'))
-        //    goto dired;
+        /* XXX: dired_mode_probe will check for wildcards in real_filename */
         put_status(s, "(New file)");
         /* Try to determine the desired mode based on the filename.
          * This avoids having to set c-mode for each new .c or .h file. */
+        b->st_mode = st_mode = S_IFREG;
         buf[0] = '\0';
-        selected_mode = probe_mode(s, filename, S_IFREG, 0, buf, 0);
-        /* XXX: avoid loading file */
-        if (selected_mode)
-            edit_set_mode(s, selected_mode);
+        buf_size = 0;
+        probe_mode(s, b, &selected_mode, 1, &mode_score, 2,
+                   b->filename, b->st_mode, b->total_size,
+                   buf, buf_size, b->charset, b->eol_type);
+
+        /* Attach buffer to window, will set default_mode
+         * XXX: this will also load the file, incorrect for non raw modes
+         */
+        b->default_mode = selected_mode;
+        switch_to_buffer(s, b);
+        do_load_qerc(s, s->b->filename);
         return;
     } else {
-        st_mode = st.st_mode;
+        b->st_mode = st_mode = st.st_mode;
         buf_size = 0;
         f = NULL;
 
@@ -5748,47 +5808,51 @@
                 goto fail;
             buf_size = fread(buf, 1, sizeof(buf) - 1, f);
             if (buf_size <= 0 && ferror(f)) {
-              fail1:
                 fclose(f);
                 f = NULL;
                 goto fail;
             }
-        }
+            /* autodetect buffer charset */
+            charset = detect_charset(buf, buf_size, &eol_type);
     }
     buf[buf_size] = '\0';
-    selected_mode = probe_mode(s, filename, st_mode, st.st_size, buf, 
buf_size);
-    if (!selected_mode)
-        goto fail1;
+        if (!probe_mode(s, b, &selected_mode, 1, &mode_score, 2,
+                        filename, b->st_mode, st.st_size,
+                        buf, buf_size, charset, eol_type)) {
+            fclose(f);
+            f = NULL;
+            goto fail;
+        }
 
     bdt = selected_mode->data_type;
-
-    /* autodetect buffer charset (could move it to raw buffer loader) */
-    if (bdt == &raw_data_type) {
-        QECharset *charset;
-        EOLType eol_type;
-
-        charset = detect_charset(buf, buf_size, &eol_type);
+        if (bdt == &raw_data_type)
         eb_set_charset(b, charset, eol_type);
-    }
 
-    /* now we can set the mode */
-    edit_set_mode_full(s, selected_mode, NULL, f);
-    do_load_qerc(s, s->b->filename);
+        if (f) {
+            /* XXX: should use f to load buffer if raw_data_type */
+            fclose(f);
+            f = NULL;
+        }
 
+        /* Attach buffer to window, will set default_mode
+         * XXX: this will also load the file, incorrect for non raw modes
+         */
+        b->default_mode = selected_mode;
+        switch_to_buffer(s, b);
     if (access(b->filename, W_OK)) {
         b->flags |= BF_READONLY;
     }
-
-    if (f) {
-        fclose(f);
-    }
+        do_load_qerc(s, s->b->filename);
 
     /* XXX: invalid place */
     edit_invalidate(s);
     return;
+    }
 
  fail:
-    put_status(s, "Could not open '%s'", filename);
+    eb_free(&b);
+
+    put_status(s, "Could not open '%s': %m", filename);
 }
 
 #if 0
@@ -5796,26 +5860,29 @@
 {
     EditState *s = opaque;
     EditBuffer *b = s->b;
-    if (size >= 1024 && !b->probed)
-        edit_set_mode(s, probe_mode(s, b->filename, S_IFREG, b->total_size, 
buf, size));
+
+    if (size >= 1024 && !b->probed) {
+        do_set_next_mode(s, 0);
+    }
 }
 
 static void load_completion_cb(void *opaque, int err)
 {
     EditState *s = opaque;
-    int st_mode;
 
-    st_mode = S_IFREG;
     /* CG: potential problem: EXXX may be negative, as in Haiku */
     if (err == -ENOENT || err == -ENOTDIR) {
         put_status(s, "(New file)");
-    } else if (err == -EISDIR) {
-        st_mode = S_IFDIR;
-    } else if (err < 0) {
+    } else
+    if (err == -EISDIR) {
+        s->b->st_mode = S_IFDIR;
+    } else
+    if (err < 0) {
         put_status(s, "Could not read file");
     }
-    if (!s->b->probed)
-        edit_set_mode(s, probe_mode(s, b->filename, st_mode, b->total_size, 
buf, size));
+    if (!s->b->probed) {
+        do_set_next_mode(s, 0);
+    }
     edit_display(s->qe_state);
     dpy_flush(&global_screen);
 }
@@ -7284,14 +7351,14 @@
 {
     eb_add_callback(s->b, eb_offset_callback, &s->offset, 0);
     eb_add_callback(s->b, eb_offset_callback, &s->offset_top, 0);
-    if (!saved_data) {
+    if (saved_data) {
+        memcpy(s, saved_data->generic_data, SAVED_DATA_SIZE);
+    } else {
         memset(s, 0, SAVED_DATA_SIZE);
         s->insert = 1;
         s->indent_size = 4;
         s->default_style = QE_STYLE_DEFAULT;
         s->wrap = WRAP_LINE;
-    } else {
-        memcpy(s, saved_data->generic_data, SAVED_DATA_SIZE);
     }
     s->hex_mode = 0;
     s->insert = 1;

Index: qe.h
===================================================================
RCS file: /sources/qemacs/qemacs/qe.h,v
retrieving revision 1.140
retrieving revision 1.141
diff -u -b -r1.140 -r1.141
--- qe.h        10 Feb 2014 20:29:26 -0000      1.140
+++ qe.h        10 Feb 2014 21:21:40 -0000      1.141
@@ -822,6 +822,8 @@
     /* CG: should instead keep a pointer to last window using this
      * buffer, even if no longer on screen
      */
+    struct ModeDef *default_mode;
+    struct ModeDef *saved_mode;
     struct ModeSavedData *saved_data;
 
     /* default mode stuff when buffer is detached from window */
@@ -833,6 +835,7 @@
 
     EditBuffer *next; /* next editbuffer in qe_state buffer list */
 
+    int st_mode;                        /* unix file mode */
     char name[MAX_BUFFERNAME_SIZE];     /* buffer name */
     char filename[MAX_FILENAME_SIZE];   /* file name */
 
@@ -1136,6 +1139,10 @@
     int line_len;
     int st_mode;     /* unix file mode */
     long total_size;
+    EOLType eol_type;
+    CharsetDecodeState charset_state;
+    QECharset *charset;
+    EditBuffer *b;
 };
 
 /* private data saved by a mode so that it can be restored when the

Index: qeconfig.h
===================================================================
RCS file: /sources/qemacs/qemacs/qeconfig.h,v
retrieving revision 1.46
retrieving revision 1.47
diff -u -b -r1.46 -r1.47
--- qeconfig.h  10 Feb 2014 20:29:26 -0000      1.46
+++ qeconfig.h  10 Feb 2014 21:21:40 -0000      1.47
@@ -383,6 +383,12 @@
           "s{Set mode: }[mode]")
     CMD1( KEY_NONE, KEY_NONE,
           "set-auto-coding", do_set_auto_coding, 1)
+    CMD1( KEY_NONE, KEY_NONE,
+          "set-auto-mode", do_set_next_mode, 0)
+    CMD1( KEY_META('m'), KEY_NONE,
+          "set-next-mode", do_set_next_mode, 1)
+    CMD1( KEY_NONE, KEY_NONE,
+          "set-previous-mode", do_set_next_mode, -1)
 
     /* tab & indent */
     CMD2( KEY_NONE, KEY_NONE,

Index: shell.c
===================================================================
RCS file: /sources/qemacs/qemacs/shell.c,v
retrieving revision 1.84
retrieving revision 1.85
diff -u -b -r1.84 -r1.85
--- shell.c     5 Feb 2014 00:56:49 -0000       1.84
+++ shell.c     10 Feb 2014 21:21:40 -0000      1.85
@@ -52,7 +52,10 @@
     TTY_STATE_STRING,
 };
 
+static int shell_signature;
+
 typedef struct ShellState {
+    void *signature;
     /* buffer state */
     int pty_fd;
     int pid; /* -1 if not launched */
@@ -256,7 +259,6 @@
     char *term;
 
     s->state = TTY_STATE_NORM;
-    s->cur_offset = 0;
     /* Should compute def_color from shell default style at display
      * time and force full redisplay upon style change.
      */
@@ -655,11 +657,25 @@
 #endif
 }
 
+static ShellState *shell_get_state(EditState *e)
+{
+    ShellState *s = e->b->priv_data;
+
+    if (s && s->signature == &shell_signature)
+        return s;
+
+    put_status(e, "Not a shell buffer");
+    return NULL;
+}
+
 /* CG: much cleaner way! */
 /* would need a kill hook as well ? */
 static void shell_display_hook(EditState *e)
 {
-    ShellState *s = e->b->priv_data;
+    ShellState *s;
+
+    if (!(s = shell_get_state(e)))
+        return;
 
     if (e->interactive)
         e->offset = s->cur_offset;
@@ -672,6 +688,9 @@
     const char *p;
     int len;
 
+    if (!s || s->signature != &shell_signature)
+        return;
+
     if (key == KEY_CTRL('o')) {
         qe_ungrab_keys();
         unget_key(key);
@@ -1222,10 +1241,14 @@
 static void shell_read_cb(void *opaque)
 {
     ShellState *s = opaque;
-    QEmacsState *qs = s->qe_state;
+    QEmacsState *qs;
     unsigned char buf[16 * 1024];
     int len, i;
 
+    if (!s || s->signature != &shell_signature)
+        return;
+
+    qs = s->qe_state;
     len = read(s->pty_fd, buf, sizeof(buf));
     if (len <= 0)
         return;
@@ -1252,11 +1275,17 @@
 static void shell_pid_cb(void *opaque, int status)
 {
     ShellState *s = opaque;
-    EditBuffer *b = s->b;
-    QEmacsState *qs = s->qe_state;
+    EditBuffer *b;
+    QEmacsState *qs;
     EditState *e;
     char buf[1024];
 
+    if (!s || s->signature != &shell_signature)
+        return;
+
+    b = s->b;
+    qs = s->qe_state;
+
     *buf = 0;
     if (s->caption) {
         time_t ti;
@@ -1348,7 +1377,11 @@
     int rows, cols;
 
     b = b0;
-    if (!b) {
+    if (b) {
+        s = b->priv_data;
+        if (s && s->signature != &shell_signature)
+            return NULL;
+    } else {
         int bf_flags = BF_SAVELOG;
         if (shell_flags & SF_COLOR)
             bf_flags |= BF_STYLE2;
@@ -1367,22 +1400,27 @@
         eb_set_charset(b, &charset_vt100, b->eol_type);
     }
 
+    s = b->priv_data;
+    if (!s) {
     s = qe_mallocz(ShellState);
     if (!s) {
         if (!b0)
             eb_free(&b);
         return NULL;
     }
+        s->signature = &shell_signature;
     b->priv_data = s;
     b->close = shell_close;
     /* Track cursor with edge effect */
     eb_add_callback(b, eb_offset_callback, &s->cur_offset, 1);
+    }
     s->b = b;
     s->pty_fd = -1;
     s->pid = -1;
     s->qe_state = qs;
     s->caption = caption;
     s->shell_flags = shell_flags;
+    s->cur_offset = b->total_size;
     tty_init(s);
 
     /* launch shell */
@@ -1421,25 +1459,52 @@
 
 static void do_shell(EditState *s, int force)
 {
-    EditBuffer *b;
+    ShellState *shs;
+    EditBuffer *b = NULL;
 
     /* CG: Should prompt for buffer name if arg:
      * find a syntax for optional string argument w/ prompt
      */
     /* find shell buffer if any */
     if (!force || force == NO_ARG) {
-        if (try_show_buffer(s, "*shell*"))
+        /* XXX: if current buffer is a shell buffer without a process,
+         * restart shell process.
+         */
+        b = s->b;
+        shs = b->priv_data;
+        if (strstart(b->name, "*shell*", NULL)
+        &&  shs && shs->signature == &shell_signature) {
+            if (shs->pid >= 0)
             return;
+        } else {
+            b = try_show_buffer(s, "*shell*");
+            if (b) {
+                shs = b->priv_data;
+                if (shs) {
+                    if (shs->signature != &shell_signature) {
+                        b = NULL;
+                    } else
+                    if (shs->pid >= 0)
+                        return;
+                }
+            }
+        }
+        if (b) {
+            /* restart shell in *shell* buffer */
+            s->offset = b->total_size;
+        }
     }
 
     /* create new buffer */
-    b = new_shell_buffer(NULL, "*shell*", "Shell process", NULL,
+    b = new_shell_buffer(b, "*shell*", "Shell process", NULL,
                          SF_COLOR | SF_INTERACTIVE);
     if (!b)
         return;
 
+    b->default_mode = &shell_mode;
     switch_to_buffer(s, b);
-    edit_set_mode(s, &shell_mode);
+    s->interactive = 1;
+    //edit_set_mode(s, &shell_mode);
 
     put_status(s, "Press C-o to toggle between shell/edit mode");
 }
@@ -1483,16 +1548,21 @@
     if (!b)
         return;
 
+    b->default_mode = &shell_mode;
     switch_to_buffer(s, b);
-    edit_set_mode(s, &shell_mode);
+    //edit_set_mode(s, &shell_mode);
 
     put_status(s, "Press C-o to toggle between shell/edit mode");
 }
 
 static void shell_move_left_right(EditState *e, int dir)
 {
+    ShellState *s;
+
+    if (!(s = shell_get_state(e)))
+        return;
+
     if (e->interactive) {
-        ShellState *s = e->b->priv_data;
         tty_write(s, dir > 0 ? s->kcuf1 : s->kcub1, -1);
     } else {
         text_move_left_right_visual(e, dir);
@@ -1501,8 +1571,12 @@
 
 static void shell_move_word_left_right(EditState *e, int dir)
 {
+    ShellState *s;
+
+    if (!(s = shell_get_state(e)))
+        return;
+
     if (e->interactive) {
-        ShellState *s = e->b->priv_data;
         tty_write(s, dir > 0 ? "\033f" : "\033b", -1);
     } else {
         text_move_word_left_right(e, dir);
@@ -1511,8 +1585,12 @@
 
 static void shell_move_up_down(EditState *e, int dir)
 {
+    ShellState *s;
+
+    if (!(s = shell_get_state(e)))
+        return;
+
     if (e->interactive) {
-        ShellState *s = e->b->priv_data;
         tty_write(s, dir > 0 ? s->kcud1 : s->kcuu1, -1);
     } else {
         text_move_up_down(e, dir);
@@ -1521,7 +1599,10 @@
 
 static void shell_scroll_up_down(EditState *e, int dir)
 {
-    ShellState *s = e->b->priv_data;
+    ShellState *s;
+
+    if (!(s = shell_get_state(e)))
+        return;
 
     e->interactive = 0;
     text_scroll_up_down(e, dir);
@@ -1530,11 +1611,15 @@
 
 static void shell_move_bol(EditState *e)
 {
+    ShellState *s;
+
+    if (!(s = shell_get_state(e)))
+        return;
+
     /* XXX: exit shell interactive mode on home / ^A */
     e->interactive = 0;
 
     if (e->interactive) {
-        ShellState *s = e->b->priv_data;
         tty_write(s, "\001", 1); /* Control-A */
     } else {
         text_move_bol(e);
@@ -1543,7 +1628,10 @@
 
 static void shell_move_eol(EditState *e)
 {
-    ShellState *s = e->b->priv_data;
+    ShellState *s;
+
+    if (!(s = shell_get_state(e)))
+        return;
 
     if (e->interactive) {
         tty_write(s, "\005", 1); /* Control-E */
@@ -1558,10 +1646,12 @@
 {
     char buf[10];
     int len;
+    ShellState *s;
 
-    if (e->interactive) {
-        ShellState *s = e->b->priv_data;
+    if (!(s = shell_get_state(e)))
+        return;
 
+    if (e->interactive) {
         if (c >= KEY_META(0) && c <= KEY_META(0xff)) {
             buf[0] = '\033';
             buf[1] = c - KEY_META(0);
@@ -1613,15 +1703,18 @@
 
 static void do_shell_toggle_input(EditState *e)
 {
+    ShellState *s;
+
+    if (!(s = shell_get_state(e)))
+        return;
+
     e->interactive = !e->interactive;
     if (e->interactive) {
-        ShellState *s = e->b->priv_data;
         if (s->grab_keys)
             qe_grab_keys(shell_key, s);
     }
 #if 0
     if (e->interactive) {
-        ShellState *s = e->b->priv_data;
         tty_update_cursor(s);
     }
 #endif
@@ -1650,7 +1743,6 @@
 
     /* XXX: try to split window if necessary */
     switch_to_buffer(e, b);
-    /* XXX: pager_mode for colorized output, text mode should support color 
buffer */ 
     edit_set_mode(e, &pager_mode);
     set_error_offset(b, 0);
 }
@@ -1815,7 +1907,17 @@
     CMD_DEF_END,
 };
 
-static int shell_mode_init(EditState *s, __unused__ ModeSavedData *saved_data)
+static int shell_mode_probe(ModeDef *mode, ModeProbeData *p)
+{
+    if (p->b && p->b->priv_data) {
+        ShellState *s = p->b->priv_data;
+        if (s->signature == &shell_signature)
+            return 100;
+    }
+    return 0;
+}
+
+static int shell_mode_init(EditState *s, ModeSavedData *saved_data)
 {
     text_mode_init(s, saved_data);
     s->b->tab_width = 8;
@@ -1824,7 +1926,7 @@
     return 0;
 }
 
-static int pager_mode_init(EditState *s, __unused__ ModeSavedData *saved_data)
+static int pager_mode_init(EditState *s, ModeSavedData *saved_data)
 {
     text_mode_init(s, saved_data);
     s->b->tab_width = 8;
@@ -1837,7 +1939,7 @@
     /* populate and register shell mode and commands */
     memcpy(&shell_mode, &text_mode, sizeof(ModeDef));
     shell_mode.name = "shell";
-    shell_mode.mode_probe = NULL;
+    shell_mode.mode_probe = shell_mode_probe;
     shell_mode.mode_init = shell_mode_init;
     shell_mode.display_hook = shell_display_hook;
     shell_mode.move_left_right = shell_move_left_right;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]