From 142e888b088be84bbf427dc19f767a0dd5cbcf6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Diego=20Aur=C3=A9lio=20Mesquita?= Date: Thu, 2 Nov 2017 04:25:03 -0200 Subject: [PATCH] Implement quick switching of open files. Hit ^R ^O to use it. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marco Diego Aurélio Mesquita --- src/browser.c | 260 ++++++++++++++++++++++++++++++++++++++-------------------- src/files.c | 22 +++++ src/global.c | 10 +++ src/proto.h | 2 + 4 files changed, 207 insertions(+), 87 deletions(-) diff --git a/src/browser.c b/src/browser.c index e1ae9938..9298755d 100644 --- a/src/browser.c +++ b/src/browser.c @@ -38,6 +38,61 @@ static int longest = 0; /* The number of columns in the longest filename in the list. */ static size_t selected = 0; /* The currently selected filename in the list; zero-based. */ +static bool file_mode = TRUE; + /* Whether we are listing files or open buffers. */ + +/* Fills filelist with a list current open files. + * Also sets longest and width. */ +void list_current_files() +{ + char *filename; + int count = 0; + filelist_len = 0; + longest = 0; + + openfilestruct *first = openfile; + openfilestruct *current = openfile; + + do { + filelist_len++; + current = current->next; + } while (first != current); + + filelist = (char **)nmalloc(filelist_len * sizeof(char *)); + + current = openfile; + + do { + size_t len; + + filename = current->filename; + filelist[count++] = filename; + + len = filename[0] == '\0' ? strlen(_("New Buffer")) : + strlen(filename); + + if (len > longest) + longest = len; + + current = current->next; + } while (first != current); + + /* Put 10 characters' worth of blank space between columns of filenames + * in the list whenever possible, as Pico does. */ + longest += 10; + + /* If needed, make room for ".. (parent dir)". */ + if (longest < 15) + longest = 15; + /* Make sure we're not wider than the window. */ + if (longest > COLS) + longest = COLS; + + /* Sort the list of names. */ + qsort(filelist, filelist_len, sizeof(char *), diralphasort); + + width = (COLS + 2) / (longest + 2); +} /* Our main file browser function. path is the tilde-expanded path we * start browsing from. */ @@ -58,50 +113,55 @@ char *do_browser(char *path) read_directory_contents: /* We come here when we refresh or select a new directory. */ - path = free_and_assign(path, get_full_path(path)); + if (file_mode) { + path = free_and_assign(path, get_full_path(path)); - if (path != NULL) - dir = opendir(path); + if (path != NULL) + dir = opendir(path); - if (path == NULL || dir == NULL) { - statusline(ALERT, _("Cannot open directory: %s"), strerror(errno)); - /* If we don't have a file list yet, there is nothing to show. */ - if (filelist == NULL) { - napms(1200); - lastmessage = HUSH; - free(path); - free(present_name); - return NULL; + if (path == NULL || dir == NULL) { + statusline(ALERT, _("Cannot open directory: %s"), strerror(errno)); + /* If we don't have a file list yet, there is nothing to show. */ + if (filelist == NULL) { + napms(1200); + lastmessage = HUSH; + free(path); + free(present_name); + return NULL; + } + path = mallocstrcpy(path, present_path); + present_name = mallocstrcpy(present_name, filelist[selected]); + } + + assert(path != NULL && path[strlen(path) - 1] == '/'); + + if (dir != NULL) { + /* Get the file list, and set longest and width in the process. */ + read_the_list(path, dir); + closedir(dir); + dir = NULL; } - path = mallocstrcpy(path, present_path); - present_name = mallocstrcpy(present_name, filelist[selected]); - } - assert(path != NULL && path[strlen(path) - 1] == '/'); + /* If given, reselect the present_name and then discard it. */ + if (present_name != NULL) { + browser_select_dirname(present_name); - if (dir != NULL) { - /* Get the file list, and set longest and width in the process. */ - read_the_list(path, dir); - closedir(dir); - dir = NULL; - } + free(present_name); + present_name = NULL; + /* Otherwise, select the first file or directory in the list. */ + } else + selected = 0; - /* If given, reselect the present_name and then discard it. */ - if (present_name != NULL) { - browser_select_dirname(present_name); + present_path = mallocstrcpy(present_path, path); - free(present_name); - present_name = NULL; - /* Otherwise, select the first file or directory in the list. */ - } else + titlebar(path); + } else { selected = 0; + list_current_files(); + } old_selected = (size_t)-1; - present_path = mallocstrcpy(present_path, path); - - titlebar(path); - while (TRUE) { lastmessage = HUSH; @@ -267,6 +327,10 @@ char *do_browser(char *path) } else if (func == do_enter) { struct stat st; + /* If listing only open files, return NULL*/ + if (!file_mode) + return NULL; + /* It isn't possible to move up from the root directory. */ if (strcmp(filelist[selected], "/..") == 0) { statusline(ALERT, _("Can't move up a directory")); @@ -329,13 +393,27 @@ char *do_browser(char *path) free(path); - free_chararray(filelist, filelist_len); - filelist = NULL; + if (file_mode) { + free_chararray(filelist, filelist_len); + filelist = NULL; + } + filelist_len = 0; return retval; } +char *do_browse_open(void) +{ + char *ret; + file_mode = FALSE; + do_browser(NULL); + ret = filelist[selected]; + free(filelist); + filelist = NULL; + return ret; +} + /* The file browser front end. We check to see if inpath has a * directory in it. If it does, we start do_browser() from there. * Otherwise, we start do_browser() from the current directory. */ @@ -345,6 +423,8 @@ char *do_browse_from(const char *inpath) char *path; /* This holds the tilde-expanded version of inpath. */ + file_mode = TRUE; + path = real_dir_from_tilde(inpath); /* Perhaps path is a directory. If so, we'll pass it to @@ -506,7 +586,9 @@ void browser_refresh(void) char *info; /* The additional information that we'll display about a file. */ - titlebar(present_path); + if (file_mode) + titlebar(present_path); + blank_edit(); wmove(edit, 0, 0); @@ -515,7 +597,9 @@ void browser_refresh(void) for (; i < filelist_len && row < editwinrows; i++) { struct stat st; - const char *thename = tail(filelist[i]); + const char *thename = file_mode ? tail(filelist[i]) : + filelist[i][0] == '\0' ? _("New Buffer") : + filelist[i]; /* The filename we display, minus the path. */ size_t namelen = strlenpt(thename); /* The length of the filename in columns. */ @@ -551,66 +635,68 @@ void browser_refresh(void) col += longest; - /* Show information about the file: "--" for symlinks (except when - * they point to a directory) and for files that have disappeared, - * "(dir)" for directories, and the file size for normal files. */ - if (lstat(filelist[i], &st) == -1 || S_ISLNK(st.st_mode)) { - if (stat(filelist[i], &st) == -1 || !S_ISDIR(st.st_mode)) - info = mallocstrcpy(NULL, "--"); - else - /* TRANSLATORS: Try to keep this at most 7 characters. */ - info = mallocstrcpy(NULL, _("(dir)")); - } else if (S_ISDIR(st.st_mode)) { - if (strcmp(thename, "..") == 0) { - /* TRANSLATORS: Try to keep this at most 12 characters. */ - info = mallocstrcpy(NULL, _("(parent dir)")); - infomaxlen = 12; - } else - info = mallocstrcpy(NULL, _("(dir)")); - } else { - off_t result = st.st_size; - char modifier; - - info = charalloc(infomaxlen + 1); - - /* Massage the file size into a human-readable form. */ - if (st.st_size < (1 << 10)) - modifier = ' '; /* bytes */ - else if (st.st_size < (1 << 20)) { - result >>= 10; - modifier = 'K'; /* kilobytes */ - } else if (st.st_size < (1 << 30)) { - result >>= 20; - modifier = 'M'; /* megabytes */ + if (file_mode) { + /* Show information about the file: "--" for symlinks (except when + * they point to a directory) and for files that have disappeared, + * "(dir)" for directories, and the file size for normal files. */ + if (lstat(filelist[i], &st) == -1 || S_ISLNK(st.st_mode)) { + if (stat(filelist[i], &st) == -1 || !S_ISDIR(st.st_mode)) + info = mallocstrcpy(NULL, "--"); + else + /* TRANSLATORS: Try to keep this at most 7 characters. */ + info = mallocstrcpy(NULL, _("(dir)")); + } else if (S_ISDIR(st.st_mode)) { + if (strcmp(thename, "..") == 0) { + /* TRANSLATORS: Try to keep this at most 12 characters. */ + info = mallocstrcpy(NULL, _("(parent dir)")); + infomaxlen = 12; + } else + info = mallocstrcpy(NULL, _("(dir)")); } else { - result >>= 30; - modifier = 'G'; /* gigabytes */ + off_t result = st.st_size; + char modifier; + + info = charalloc(infomaxlen + 1); + + /* Massage the file size into a human-readable form. */ + if (st.st_size < (1 << 10)) + modifier = ' '; /* bytes */ + else if (st.st_size < (1 << 20)) { + result >>= 10; + modifier = 'K'; /* kilobytes */ + } else if (st.st_size < (1 << 30)) { + result >>= 20; + modifier = 'M'; /* megabytes */ + } else { + result >>= 30; + modifier = 'G'; /* gigabytes */ + } + + /* Show the size if less than a terabyte, else show "(huge)". */ + if (result < (1 << 10)) + sprintf(info, "%4ju %cB", (intmax_t)result, modifier); + else + /* TRANSLATORS: Try to keep this at most 7 characters. + * If necessary, you can leave out the parentheses. */ + info = mallocstrcpy(info, _("(huge)")); } - /* Show the size if less than a terabyte, else show "(huge)". */ - if (result < (1 << 10)) - sprintf(info, "%4ju %cB", (intmax_t)result, modifier); - else - /* TRANSLATORS: Try to keep this at most 7 characters. - * If necessary, you can leave out the parentheses. */ - info = mallocstrcpy(info, _("(huge)")); - } + /* Make sure info takes up no more than infomaxlen columns. */ + infolen = strlenpt(info); + if (infolen > infomaxlen) { + info[actual_x(info, infomaxlen)] = '\0'; + infolen = infomaxlen; + } - /* Make sure info takes up no more than infomaxlen columns. */ - infolen = strlenpt(info); - if (infolen > infomaxlen) { - info[actual_x(info, infomaxlen)] = '\0'; - infolen = infomaxlen; - } + mvwaddstr(edit, row, col - infolen, info); - mvwaddstr(edit, row, col - infolen, info); + free(info); + } /* If this is the selected item, finish its highlighting. */ if (i == selected) wattroff(edit, interface_color_pair[SELECTED_TEXT]); - free(info); - /* Add some space between the columns. */ col += 2; diff --git a/src/files.c b/src/files.c index 28a71a41..035dbc70 100644 --- a/src/files.c +++ b/src/files.c @@ -32,6 +32,8 @@ #define LOCKBUFSIZE 8192 +void switch_to_buffer(openfilestruct *target); + /* Verify that the containing directory of the given filename exists. */ bool has_valid_path(const char *filename) { @@ -598,6 +600,12 @@ void switch_to_adjacent_buffer(bool to_next) /* Switch to the next or previous file buffer. */ openfile = to_next ? openfile->next : openfile->prev; + switch_to_buffer(openfile); +} + +void switch_to_buffer(openfilestruct *target) +{ + openfile = target; #ifndef NANO_TINY /* When not in softwrap mode, make sure firstcolumn is zero. It might @@ -1115,6 +1123,20 @@ void do_insertfile(void) answer = chosen; i = 0; } + + if (func == to_open_void) { + openfilestruct *current = openfile; + char *chosen = do_browse_open(); + + do { + if (current->filename == chosen) + break; + current = current->next; + } while (current != openfile); + + switch_to_buffer(current); + break; + } #endif /* If we don't have a file yet, go back to the prompt. */ if (i != 0 && (!ISSET(MULTIBUFFER) || i != -2)) diff --git a/src/global.c b/src/global.c index 10097aaf..5ff21c2c 100644 --- a/src/global.c +++ b/src/global.c @@ -283,6 +283,9 @@ void gototext_void(void) void to_files_void(void) { } +void to_open_void(void) +{ +} void goto_dir_void(void) { } @@ -663,6 +666,7 @@ void shortcut_init(void) const char *discardbuffer_gist = N_("Close buffer without saving it"); #ifdef ENABLE_BROWSER const char *tofiles_gist = N_("Go to file browser"); + const char *toopen_gist = N_("Browse open files"); const char *exitbrowser_gist = N_("Exit from the file browser"); const char *firstfile_gist = N_("Go to the first file in the list"); const char *lastfile_gist = N_("Go to the last file in the list"); @@ -1048,6 +1052,9 @@ void shortcut_init(void) add_to_funcs(to_files_void, MWRITEFILE|MINSERTFILE, N_("To Files"), WITHORSANS(tofiles_gist), TOGETHER, VIEW); + add_to_funcs(to_open_void, MINSERTFILE, + N_("To Open"), WITHORSANS(toopen_gist), TOGETHER, VIEW); + add_to_funcs(do_page_up, MBROWSER, prevpage_tag, WITHORSANS(prevpage_gist), TOGETHER, VIEW); add_to_funcs(do_page_down, MBROWSER, @@ -1335,6 +1342,7 @@ void shortcut_init(void) /* In restricted mode, don't allow entering the file browser. */ if (!ISSET(RESTRICTED)) add_to_sclist(MWRITEFILE|MINSERTFILE, "^T", 0, to_files_void, 0); + add_to_sclist(MINSERTFILE, "^O", 0, to_open_void, 0); #endif add_to_sclist(MHELP|MBROWSER, "^C", 0, do_exit, 0); /* Allow exiting from the file browser and the help viewer with @@ -1655,6 +1663,8 @@ sc *strtosc(const char *input) else if (!strcasecmp(input, "tofiles") || !strcasecmp(input, "browser")) s->scfunc = to_files_void; + else if (!strcasecmp(input, "toopen")) + s->scfunc = to_open_void; else if (!strcasecmp(input, "gotodir")) s->scfunc = goto_dir_void; else if (!strcasecmp(input, "firstfile")) diff --git a/src/proto.h b/src/proto.h index e72e6630..13d57540 100644 --- a/src/proto.h +++ b/src/proto.h @@ -187,6 +187,7 @@ typedef void (*functionptrtype)(void); /* Most functions in browser.c. */ #ifdef ENABLE_BROWSER char *do_browse_from(const char *inpath); +char *do_browse_open(void); void read_the_list(const char *path, DIR *dir); functionptrtype parse_browser_input(int *kbinput); void browser_refresh(void); @@ -704,6 +705,7 @@ void flip_replace(void); void gototext_void(void); #ifdef ENABLE_BROWSER void to_files_void(void); +void to_open_void(void); void goto_dir_void(void); #endif #ifndef NANO_TINY -- 2.11.0