]> git.wh0rd.org Git - nano.git/commitdiff
Added tab completion code
authorChris Allegretta <chrisa@asty.org>
Sun, 5 Nov 2000 17:54:41 +0000 (17:54 +0000)
committerChris Allegretta <chrisa@asty.org>
Sun, 5 Nov 2000 17:54:41 +0000 (17:54 +0000)
git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@267 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
files.c
po/nano.pot
proto.h
utils.c
winio.c

index 9c7e0c548a5a304d70d56503917a6835c99ed776..1390d27d02ef42652615aa78b394fa5efb59c8fb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -19,6 +19,9 @@ CVS Code -
          New functions search_init_globals and do_replace_loop, changes
          to search_init(), do_replace, findnextstr, moved last_search and
          last_replace back to nano.c (*shrug*).
+       - New tab completion code.  Used check_wildcard_match, input_tab, 
+         cwd_tab_completion, username_tab_completion from busybox, 
+         hacked them a lot, changes to nanogetstr().
 - files.c:
   do_writeout()
        - Change strcpy to answer to mallocstrcpy.
@@ -59,8 +62,8 @@ CVS Code -
          into statusbar" bug in odd $TERMs like iris-ansi.
        - Changed check to return -2 on "enter" from answer == ""
          to answer == def.
-       - Silly kludge in backspace code to temporarily decrement x
-         before refreshing to keep the cursor visually aligned.
+       - Fixed fallthrough code because there was no break.  Make much
+         more sense now.
   nanoget_repaint()
        - New function, removes about 30 lines of duplicate code in 
          nanogetstr().
diff --git a/files.c b/files.c
index 6b871e3749b54608f871c08d5c9d3b0ada7260c2..c6279d70ba214ace71f75ed493cdcd3ea053e303 100644 (file)
--- a/files.c
+++ b/files.c
@@ -27,6 +27,8 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <errno.h>
+#include <ctype.h>
+#include <dirent.h>
 
 #include "config.h"
 #include "proto.h"
@@ -494,3 +496,193 @@ int do_writeout_void(void)
 {
     return do_writeout(0);
 }
+
+
+/*
+ * These functions (username_tab_completion, cwd_tab_completion, and
+ * input_tab were taken from busybox 0.46 (cmdedit.c).  Here is the notice
+ * from that file:
+ *
+ * Termios command line History and Editting, originally
+ * intended for NetBSD sh (ash)
+ * Copyright (c) 1999
+ *      Main code:            Adam Rogoyski <rogoyski@cs.utexas.edu>
+ *      Etc:                  Dave Cinege <dcinege@psychosis.com>
+ *  Majorly adjusted/re-written for busybox:
+ *                            Erik Andersen <andersee@debian.org>
+ *
+ * You may use this code as you wish, so long as the original author(s)
+ * are attributed in any redistributions of the source code.
+ * This code is 'as is' with no warranty.
+ * This code may safely be consumed by a BSD or GPL license.
+ */
+
+char **username_tab_completion(char *buf, int *num_matches)
+{
+    char **matches = (char **) NULL;
+    *num_matches = 0;
+#ifdef DEBUG
+    fprintf(stderr, "\nin username_tab_completion\n");
+#endif
+    return (matches);
+}
+
+/* This was originally called exe_n_cwd_tab_completion, but we're not
+   worried about executables, only filenames :> */
+
+char **cwd_tab_completion(char *buf, int *num_matches)
+{
+    char *dirName, *tmp = NULL;
+    char **matches = (char **) NULL;
+    DIR *dir;
+    struct dirent *next;
+
+    matches = malloc(sizeof(char *) * 50);
+
+    /* Stick a wildcard onto the buf, for later use */
+    strcat(buf, "*");
+
+    /* Now wall the current directory */
+/*    if (!strcmp(filename, ""))
+       dirName = get_current_dir_name(); */
+
+    if (strcmp(buf, "") && strstr(buf, "/")) {
+       dirName = malloc(strlen(buf) + 1);
+       tmp = buf + strlen(buf);
+       while (*tmp != '/' && tmp != buf)
+          tmp--;
+       strncpy(dirName, buf, tmp - buf);
+       dirName[tmp - buf] = 0;
+       tmp++;
+
+    } else {
+       if ((dirName = getcwd(NULL, 0)) == NULL)
+           return matches;
+       else
+           tmp = buf;
+    }
+
+#ifdef DEBUG
+    fprintf(stderr, "\nDir = %s\n", dirName);
+    fprintf(stderr, "\nbuf = %s\n", buf);
+    fprintf(stderr, "\ntmp = %s\n", tmp);
+#endif
+    
+    dir = opendir(dirName);
+    if (!dir) {
+       /* Don't print an error, just shut up and return */
+       *num_matches = 0;
+       beep();
+       return (matches);
+    }
+    while ((next = readdir(dir)) != NULL) {
+
+       /* Some quick sanity checks */
+       if ((strcmp(next->d_name, "..") == 0)
+           || (strcmp(next->d_name, ".") == 0)) {
+           continue;
+       }
+#ifdef DEBUG
+       fprintf(stderr, "\nComparing \'%s\'\n", next->d_name);
+#endif
+       /* See if this matches */
+       if (check_wildcard_match(next->d_name, tmp) == TRUE) {
+           /* Cool, found a match.  Add it to the list */
+           matches[*num_matches] = malloc(strlen(next->d_name) + 1);
+           strcpy(matches[*num_matches], next->d_name);
+           ++*num_matches;
+           //matches = realloc( matches, sizeof(char*)*(*num_matches));
+       }
+    }
+
+    return (matches);
+}
+
+/* This function now return an int which refers to how much the 
+ * statusbar (place) should be advanced, i.e. the new cursor pos.
+ */
+int input_tab(char *buf, int place, int lastWasTab)
+{
+    /* Do TAB completion */
+    static int num_matches = 0;
+    static char **matches = (char **) NULL;
+    int pos = place, newplace = 0;
+
+    if (lastWasTab == FALSE) {
+       char *tmp, *matchBuf;
+
+       /* For now, we will not bother with trying to distinguish
+        * whether the cursor is in/at a command extression -- we
+        * will always try all possible matches.  If you don't like
+        * that then feel free to fix it.
+        */
+
+       /* Make a local copy of the string -- up to the position of the
+          cursor */
+       matchBuf = (char *) calloc(strlen(buf), sizeof(char));
+       strncpy(matchBuf, buf, place);
+       tmp = matchBuf;
+
+       /* skip any leading white space */
+       while (*tmp && isspace(*tmp))
+           ++tmp;
+
+       /* Free up any memory already allocated */
+       if (matches != NULL) {
+           free(matches);
+           matches = (char **) NULL;
+       }
+
+       /* If the word starts with `~' and there is no slash in the word, 
+        * then try completing this word as a username. */
+
+       /* FIXME -- this check is broken!
+       if (*tmp == '~' && !strchr(tmp, '/'))
+           matches = username_tab_completion(tmp, &num_matches); */
+
+       /* Try to match everything in the current working directory that
+        * matches.  */
+       if (!matches)
+           matches = cwd_tab_completion(tmp, &num_matches);
+
+       /* Don't leak memory */
+       free(matchBuf);
+
+       /* Did we find exactly one match? */
+       if (matches && num_matches == 1) {
+           buf = nrealloc(buf, strlen(buf) + strlen(matches[0]) - pos + 1);
+           /* write out the matched command */
+           strncpy(buf + pos, matches[0] + pos,
+                   strlen(matches[0]) - pos);
+           newplace += strlen(matches[0]) - pos;
+       }
+    } else {
+       /* Ok -- the last char was a TAB.  Since they
+        * just hit TAB again, print a list of all the
+        * available choices... */
+       if (matches && num_matches > 0) {
+           int i, col;
+
+           /* Blank the edit window, and print the matches out there */
+           blank_edit();
+           wmove(edit, 0, 0);
+
+           /* Print the list of matches */
+           for (i = 0, col = 0; i < num_matches; i++) {
+               char foo[17];
+               sprintf(foo, "%-14s  ", matches[i]);
+               col += waddnstr(edit, foo, strlen(foo));
+               if (col > 60 && matches[i + 1] != NULL) {
+                   waddstr(edit, "\n");
+                   col = 0;
+               }
+           }
+           wrefresh(edit);
+           num_matches = 0;
+       }
+
+    }
+
+    edit_refresh();
+    return newplace;
+}
index 914d75450bf89b983b38ec65bfa521339b28d253..95853cbd41cb94fcff7cf346c5284a8c07a3f52d 100644 (file)
@@ -6,7 +6,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
-"POT-Creation-Date: 2000-11-05 11:52-0500\n"
+"POT-Creation-Date: 2000-11-05 12:08-0500\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -23,87 +23,87 @@ msgstr ""
 msgid "Blew away cutbuffer =)\n"
 msgstr ""
 
-#: files.c:120
+#: files.c:122
 msgid "read_line: not on first line and prev is NULL"
 msgstr ""
 
-#: files.c:182 files.c:199
+#: files.c:184 files.c:201
 #, c-format
 msgid "Read %d lines"
 msgstr ""
 
-#: files.c:217 search.c:164
+#: files.c:219 search.c:164
 #, c-format
 msgid "\"%s\" not found"
 msgstr ""
 
 #. We have a new file
-#: files.c:221
+#: files.c:223
 msgid "New File"
 msgstr ""
 
-#: files.c:230
+#: files.c:232
 #, c-format
 msgid "File \"%s\" is a directory"
 msgstr ""
 
-#: files.c:236
+#: files.c:238
 msgid "Reading File"
 msgstr ""
 
-#: files.c:249
+#: files.c:251
 msgid "File to insert [from ./] "
 msgstr ""
 
-#: files.c:274 files.c:298 files.c:486 nano.c:1347
+#: files.c:276 files.c:300 files.c:488 nano.c:1347
 msgid "Cancelled"
 msgstr ""
 
-#: files.c:320 files.c:340 files.c:354 files.c:371 files.c:377
+#: files.c:322 files.c:342 files.c:356 files.c:373 files.c:379
 #, c-format
 msgid "Could not open file for writing: %s"
 msgstr ""
 
-#: files.c:328
+#: files.c:330
 msgid "Could not open file: Path length exceeded."
 msgstr ""
 
-#: files.c:359
+#: files.c:361
 #, c-format
 msgid "Wrote >%s\n"
 msgstr ""
 
-#: files.c:386
+#: files.c:388
 #, c-format
 msgid "Could not close %s: %s"
 msgstr ""
 
 #. Try a rename??
-#: files.c:407 files.c:418 files.c:423
+#: files.c:409 files.c:420 files.c:425
 #, c-format
 msgid "Could not open %s for writing: %s"
 msgstr ""
 
-#: files.c:429
+#: files.c:431
 #, c-format
 msgid "Could not set permissions %o on %s: %s"
 msgstr ""
 
-#: files.c:436
+#: files.c:438
 #, c-format
 msgid "Wrote %d lines"
 msgstr ""
 
-#: files.c:465
+#: files.c:467
 msgid "File Name to write"
 msgstr ""
 
-#: files.c:470
+#: files.c:472
 #, c-format
 msgid "filename is %s"
 msgstr ""
 
-#: files.c:475
+#: files.c:477
 msgid "File exists, OVERWRITE ?"
 msgstr ""
 
@@ -380,7 +380,7 @@ msgid "Case Sens"
 msgstr ""
 
 #: global.c:344 global.c:364 global.c:375 global.c:385 global.c:401
-#: global.c:405 global.c:411 winio.c:993
+#: global.c:405 global.c:411 winio.c:1009
 msgid "Cancel"
 msgstr ""
 
@@ -817,67 +817,67 @@ msgstr ""
 msgid "actual_x_from_start for xplus=%d returned %d\n"
 msgstr ""
 
-#: winio.c:408
+#: winio.c:424
 #, c-format
 msgid "input '%c' (%d)\n"
 msgstr ""
 
-#: winio.c:446
+#: winio.c:462
 msgid "New Buffer"
 msgstr ""
 
-#: winio.c:449
+#: winio.c:465
 msgid "  File: ..."
 msgstr ""
 
-#: winio.c:457
+#: winio.c:473
 msgid "Modified"
 msgstr ""
 
-#: winio.c:909
+#: winio.c:925
 #, c-format
 msgid "Moved to (%d, %d) in edit buffer\n"
 msgstr ""
 
-#: winio.c:920
+#: winio.c:936
 #, c-format
 msgid "current->data = \"%s\"\n"
 msgstr ""
 
-#: winio.c:963
+#: winio.c:979
 #, c-format
 msgid "I got \"%s\"\n"
 msgstr ""
 
-#: winio.c:988
+#: winio.c:1004
 msgid "Yes"
 msgstr ""
 
-#: winio.c:990
+#: winio.c:1006
 msgid "All"
 msgstr ""
 
-#: winio.c:992
+#: winio.c:1008
 msgid "No"
 msgstr ""
 
-#: winio.c:1129
+#: winio.c:1145
 #, c-format
 msgid "do_cursorpos: linepct = %f, bytepct = %f\n"
 msgstr ""
 
-#: winio.c:1133
+#: winio.c:1149
 msgid "line %d of %d (%.0f%%), character %d of %d (%.0f%%)"
 msgstr ""
 
-#: winio.c:1261
+#: winio.c:1277
 msgid "Dumping file buffer to stderr...\n"
 msgstr ""
 
-#: winio.c:1263
+#: winio.c:1279
 msgid "Dumping cutbuffer to stderr...\n"
 msgstr ""
 
-#: winio.c:1265
+#: winio.c:1281
 msgid "Dumping a buffer to stderr...\n"
 msgstr ""
diff --git a/proto.h b/proto.h
index be689f0e2cb7fccb0a0c57101bed0b78301c3ffd..cf7a5d8a02f84346faf1116e36144e3a5207e3f7 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -87,7 +87,8 @@ int do_up(void);
 int do_down(void);
 int do_left(void);
 int do_right(void);
-
+int check_wildcard_match(const char *text, const char *pattern);
+int input_tab(char *buf, int place, int lastWasTab);
 
 void shortcut_init(void);
 void lowercase(char *src);
@@ -125,6 +126,7 @@ void new_magicline(void);
 void splice_node(filestruct *begin, filestruct *new, filestruct *end);
 void null_at(char *data, int index);
 void page_up_center(void);
+void blank_edit(void);
 void search_init_globals(void);
 void replace_abort(void);
 
diff --git a/utils.c b/utils.c
index f538de7aa851fbddecbbb640e72da8e28dd358c2..4b248053e97284c50df30965c9648341c0c739db 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -148,3 +148,103 @@ void new_magicline(void)
     filebot = filebot->next;
     totlines++;
 }
+
+/*
+ * Routine to see if a text string is matched by a wildcard pattern.
+ * Returns TRUE if the text is matched, or FALSE if it is not matched
+ * or if the pattern is invalid.
+ *  *          matches zero or more characters
+ *  ?          matches a single character
+ *  [abc]      matches 'a', 'b' or 'c'
+ *  \c         quotes character c
+ * Adapted from code written by Ingo Wilken, and
+ * then taken from sash, Copyright (c) 1999 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ * Permission to distribute this code under the GPL has been granted.
+ */
+int check_wildcard_match(const char *text, const char *pattern)
+{
+    const char *retryPat;
+    const char *retryText;
+    int ch;
+    int found;
+    int len;
+
+    retryPat = NULL;
+    retryText = NULL;
+
+    while (*text || *pattern) {
+       ch = *pattern++;
+
+       switch (ch) {
+       case '*':
+           retryPat = pattern;
+           retryText = text;
+           break;
+
+       case '[':
+           found = FALSE;
+
+           while ((ch = *pattern++) != ']') {
+               if (ch == '\\')
+                   ch = *pattern++;
+
+               if (ch == '\0')
+                   return FALSE;
+
+               if (*text == ch)
+                   found = TRUE;
+           }
+           len = strlen(text);
+           if (found == FALSE && len != 0) {
+               return FALSE;
+           }
+           if (found == TRUE) {
+               if (strlen(pattern) == 0 && len == 1) {
+                   return TRUE;
+               }
+               if (len != 0) {
+                   text++;
+                   continue;
+               }
+           }
+
+           /* fall into next case */
+
+       case '?':
+           if (*text++ == '\0')
+               return FALSE;
+
+           break;
+
+       case '\\':
+           ch = *pattern++;
+
+           if (ch == '\0')
+               return FALSE;
+
+           /* fall into next case */
+
+       default:
+           if (*text == ch) {
+               if (*text)
+                   text++;
+               break;
+           }
+
+           if (*text) {
+               pattern = retryPat;
+               text = ++retryText;
+               break;
+           }
+
+           return FALSE;
+       }
+
+       if (pattern == NULL)
+           return FALSE;
+    }
+
+    return TRUE;
+}
diff --git a/winio.c b/winio.c
index ab6c511dce78fa7b7cab84457859f9ed761fc36a..5a200502c47b8260fa9ba07c6b11b303b824a1d7 100644 (file)
--- a/winio.c
+++ b/winio.c
@@ -247,7 +247,7 @@ void nanoget_repaint(char *buf, char *inputbuf, int x)
 int nanogetstr(char *buf, char *def, shortcut s[], int slen, int start_x)
 {
     int kbinput = 0, j = 0, x = 0, xend;
-    int x_left = 0, inputlen;
+    int x_left = 0, inputlen, tabbed = 0;
     char *inputbuf;
     
     inputbuf = nmalloc(strlen(def) + 1);
@@ -272,6 +272,9 @@ int nanogetstr(char *buf, char *def, shortcut s[], int slen, int start_x)
        }
        xend = strlen(buf) + strlen(inputbuf);
 
+       if (kbinput != '\t')
+           tabbed = 0;
+
        switch (kbinput) {
            /* Stuff we want to equate with <enter>, ASCII 13 */
        case 343:
@@ -321,9 +324,22 @@ int nanogetstr(char *buf, char *def, shortcut s[], int slen, int start_x)
                    inputbuf[strlen(inputbuf) - 1] = 0;
                }
            }
-           x--;
+           if (x > strlen(buf))
+               x--;
            nanoget_repaint(buf, inputbuf, x);
-           x++;
+           break;
+       case NANO_CONTROL_I:
+           tabbed++;
+#ifdef DEBUG
+           fprintf(stderr, "Before call, x = %d\n", x);
+#endif
+           x += input_tab(inputbuf, (x - x_left), tabbed - 1);
+#ifdef DEBUG
+           fprintf(stderr, "After call, x = %d\n", x);
+#endif
+           nanoget_repaint(buf, inputbuf, x);
+           tabbed = 1;
+           break;
        case KEY_LEFT:
            if (x > strlen(buf))
                x--;