diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2014-11-22 05:31:31 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2014-11-22 05:31:31 +0100 |
commit | 427c9d16ce7e62cbe2671748cd8434132ce60482 (patch) | |
tree | b3b4657c8178dcc9308790abaa1c2cf9bbc4c09b /src | |
parent | 28fd3dbdc831f28c91d521e1804a9d9ff5bbf3db (diff) | |
download | sciteco-427c9d16ce7e62cbe2671748cd8434132ce60482.tar.gz |
added globbing command EN
* implements the same globbing as the EB command already did
* uses Globber helper class that behaves more like UNIX glob().
glib only has a glob-style pattern matcher.
* The Globber class may be extended later to provide more
UNIX-like globbing.
* lexer.tes has been updated to make use of globbing.
Now, lexers can be automatically loaded and registered at
startup. To install a new lexer, it's sufficient to copy
a file to the lexers/ directory.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/cmdline.cpp | 1 | ||||
-rw-r--r-- | src/glob.cpp | 152 | ||||
-rw-r--r-- | src/glob.h | 66 | ||||
-rw-r--r-- | src/parser.cpp | 2 | ||||
-rw-r--r-- | src/ring.cpp | 41 | ||||
-rw-r--r-- | src/ring.h | 6 |
7 files changed, 231 insertions, 38 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index af324e0..d02c0b5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,6 +30,7 @@ libsciteco_base_a_SOURCES = main.cpp sciteco.h \ parser.cpp parser.h \ search.cpp search.h \ spawn.cpp spawn.h \ + glob.cpp glob.h \ goto.cpp goto.h \ rbtree.cpp rbtree.h \ symbols.cpp symbols.h \ diff --git a/src/cmdline.cpp b/src/cmdline.cpp index e78db60..8b2d412 100644 --- a/src/cmdline.cpp +++ b/src/cmdline.cpp @@ -36,6 +36,7 @@ #include "undo.h" #include "symbols.h" #include "spawn.h" +#include "glob.h" #include "error.h" #include "cmdline.h" diff --git a/src/glob.cpp b/src/glob.cpp new file mode 100644 index 0000000..71100b7 --- /dev/null +++ b/src/glob.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2012-2014 Robin Haberkorn + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> + +#include <glib.h> + +#include "sciteco.h" +#include "interface.h" +#include "parser.h" +#include "ring.h" +#include "glob.h" + +namespace SciTECO { + +namespace States { + StateGlob glob; +} + +Globber::Globber(const gchar *_pattern) +{ + gchar *basename; + + dirname = g_path_get_dirname(_pattern); + dir = g_dir_open(dirname, 0, NULL); + + basename = g_path_get_basename(_pattern); + pattern = g_pattern_spec_new(basename); + g_free(basename); +} + +gchar * +Globber::next(void) +{ + const gchar *basename; + + while ((basename = g_dir_read_name(dir))) + if (g_pattern_match_string(pattern, basename)) + return g_build_filename(dirname, basename, NIL); + + return NULL; +} + +Globber::~Globber() +{ + if (pattern) + g_pattern_spec_free(pattern); + if (dir) + g_dir_close(dir); + g_free(dirname); +} + +/* + * Command States + */ + +/*$ + * EN[pattern]$ -- Get list of files matching a glob pattern + * + * The EN command expands a glob \fIpattern\fP to a list of + * matching file names. This is similar to globbing + * on UNIX but not as powerful. + * A \fIpattern\fP is a file name with \(lq*\(rq and + * \(lq?\(rq wildcards: + * \(lq*\(rq matches an arbitrary, possibly empty, string. + * \(lq?\(rq matches an arbitrary character. + * + * EN will currently only match files in the file name component + * of \fIpattern\fP, not on each component of the path name + * separately. + * In other words, EN only looks through the directory + * of \fIpattern\fP \(em you cannot effectively match + * multiple directories. + * + * The result of the globbing is inserted into the current + * document, at the current position. + * A linefeed is inserted after every file name, i.e. + * every matching file will be on its own line. + * + * String-building characters are enabled for EN. + */ +/* + * NOTE: This does not work like classic TECO's + * EN command (iterative globbing), since the + * position in the directory cannot be reasonably + * reset on rubout with glib's API. + * If we have to perform all the globbing on initialization + * we can just as well return all the results at once. + * And we can add them to the current document since + * when they should be in a register, the user will + * have to edit that register anyway. + */ +State * +StateGlob::done(const gchar *str) +{ + BEGIN_EXEC(&States::start); + + Globber globber(str); + + gchar *filename; + bool text_added = false; + + interface.ssm(SCI_BEGINUNDOACTION); + + while ((filename = globber.next())) { + size_t len = strlen(filename); + /* overwrite trailing null */ + filename[len] = '\n'; + + /* + * FIXME: Once we're 8-bit clean, we should + * add the filenames null-terminated + * (there may be linebreaks in filename). + */ + interface.ssm(SCI_ADDTEXT, len+1, + (sptr_t)filename); + + g_free(filename); + text_added = true; + } + + interface.ssm(SCI_SCROLLCARET); + interface.ssm(SCI_ENDUNDOACTION); + + if (text_added) { + ring.dirtify(); + if (current_doc_must_undo()) + interface.undo_ssm(SCI_UNDO); + } + + return &States::start; +} + +} /* namespace SciTECO */ diff --git a/src/glob.h b/src/glob.h new file mode 100644 index 0000000..6652d1d --- /dev/null +++ b/src/glob.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012-2014 Robin Haberkorn + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __GLOB_H +#define __GLOB_H + +#include <string.h> + +#include <glib.h> + +#include "sciteco.h" +#include "parser.h" + +namespace SciTECO { + +/* + * Auxiliary functions + */ +static inline bool +is_glob_pattern(const gchar *str) +{ + return strchr(str, '*') || strchr(str, '?'); +} + +class Globber { + gchar *dirname; + GDir *dir; + GPatternSpec *pattern; + +public: + Globber(const gchar *pattern); + ~Globber(); + + gchar *next(void); +}; + +/* + * Command states + */ + +class StateGlob : public StateExpectFile { +private: + State *done(const gchar *str); +}; + +namespace States { + extern StateGlob glob; +} + +} /* namespace SciTECO */ + +#endif diff --git a/src/parser.cpp b/src/parser.cpp index 3c991fc..6995a6b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -37,6 +37,7 @@ #include "symbols.h" #include "search.h" #include "spawn.h" +#include "glob.h" #include "cmdline.h" #include "error.h" @@ -1801,6 +1802,7 @@ StateECommand::StateECommand() : State() transitions['C'] = &States::executecommand; transitions['G'] = &States::egcommand; transitions['M'] = &States::macro_file; + transitions['N'] = &States::glob; transitions['S'] = &States::scintilla_symbols; transitions['Q'] = &States::eqcommand; transitions['W'] = &States::savefile; diff --git a/src/ring.cpp b/src/ring.cpp index 575d0e7..03cda37 100644 --- a/src/ring.cpp +++ b/src/ring.cpp @@ -38,8 +38,9 @@ #include "parser.h" #include "expressions.h" #include "qregisters.h" -#include "ring.h" +#include "glob.h" #include "error.h" +#include "ring.h" #ifdef HAVE_WINDOWS_H /* here it shouldn't cause conflicts with other headers */ @@ -600,8 +601,10 @@ StateEditFile::do_edit(tecoInt id) * Naturally this only has any effect in interactive * mode. * - * <file> may also be a glob-pattern, in which case + * <file> may also be a glob pattern, in which case * all files matching the pattern are opened/edited. + * Globbing is performed exactly the same as the + * EN command does. * * File names of buffers in the ring are normalized * by making them absolute. @@ -661,37 +664,11 @@ StateEditFile::done(const gchar *str) } if (is_glob_pattern(str)) { - gchar *dirname; - GDir *dir; - - dirname = g_path_get_dirname(str); - dir = g_dir_open(dirname, 0, NULL); - - if (dir) { - const gchar *basename; - GPatternSpec *pattern; - - basename = g_path_get_basename(str); - pattern = g_pattern_spec_new(basename); - g_free((gchar *)basename); - - while ((basename = g_dir_read_name(dir))) { - if (g_pattern_match_string(pattern, basename)) { - gchar *filename; - - filename = g_build_filename(dirname, - basename, - NIL); - do_edit(filename); - g_free(filename); - } - } - - g_pattern_spec_free(pattern); - g_dir_close(dir); - } + Globber globber(str); + gchar *filename; - g_free(dirname); + while ((filename = globber.next())) + do_edit(filename); } else { do_edit(*str ? str : NULL); } @@ -18,7 +18,6 @@ #ifndef __RING_H #define __RING_H -#include <string.h> #include <bsd/sys/queue.h> #include <glib.h> @@ -38,11 +37,6 @@ namespace SciTECO { /* * Auxiliary functions */ -static inline bool -is_glob_pattern(const gchar *str) -{ - return strchr(str, '*') || strchr(str, '?'); -} /* * Get absolute/full version of a possibly relative path. |