Up Next:
+* rename to tide
+* Change PageUp/Dn to move cursor by screenfuls
+* Add Ctrl+Shift+A shortcut to select all
* ctrl+d with no selection does word selection instead of context
-* get rid of edit wrapper script
* move by words is inconsistent. Example:
var infoId = 'readerinfo'+reader.id;
-* rename to tide
-
-* Add a way to CD using a builtin
-* Ctrl+PageUp/Dn to move cursor by screenfuls
-* Ctrl+\ Shortcut to warp cursor to middle of current screen.
-* Find shortcut should select previous word if current char is newline
-* diagnostic messages can stack up if deselected and not resolved
-* highlight all matches of search term
+* Add a way to CD using a builtin (buffers will track original dir)
* Ctrl+Shift+Enter copies indent of wrong line
-* jump to previous or next line with less indent
* Shift+Insert should insert primary selection
The Future:
+* highlight all matches of search term
* Make Fn keys execute nth command in the tags buffers
+* jump to previous or next line with less indent
* use transaction ids to only mark buffer dirty when it really is
* refactor selection handling to buf.c to prepare for multiple selections.
* 100% coverage with unit and unit-integration tests
* implement command diffing logic to optimize the undo/redo log
* Status line should omit characters from beginning of path to make file path fit
+Maybe think about addressing these later:
+
+* Find shortcut should select previous word if current char is newline
+* Ctrl+\ Shortcut to warp cursor to middle of current screen.
+* diagnostic messages can stack up if deselected and not resolved
+
# Auxillary Programs
* Visual diff tool
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
-.TH "EDIT" "1" "March 2017" "" ""
+.TH "EDIT" "1" "May 2017" "" ""
.
.SH "NAME"
\fBedit\fR \- convenience script for launching xedit(1) with a proper environment
\fBedit\fR [\fIfile\fR\.\.\.]
.
.SH "DESCRIPTION"
-This script acts as a wrapper around xedit(1)\. It is responsible for setting up the environment variables and loading the rc file xedit(1) before launching a new instance of xedit(1) for each file provided on the command line\. If no files are provided, xedit(1) will be launched to edit a scratch buffer\.
+This script acts as a wrapper around xedit(1)\. It is responsible for setting up the environment variables and loading the rc file before launching a new instance of xedit(1) to edit the given files\. If no files are provided a new instance of xedit(1) will be launched with an empty edit buffer\.
.
.SH "FILES"
.
## DESCRIPTION
This script acts as a wrapper around xedit(1). It is responsible for setting up
-the environment variables and loading the rc file xedit(1) before launching a
-new instance of xedit(1) for each file provided on the command line. If no files
-are provided, xedit(1) will be launched to edit a scratch buffer.
+the environment variables and loading the rc file before launching a
+new instance of xedit(1) to edit the given files. If no files are provided a new
+instance of xedit(1) will be launched with an empty edit buffer.
## FILES
* `$HOME/.config/edit/editrc`:
- Shell script loaded in current environment to make shell functions and
+ Shell script loaded in current environment to make shell functions and
environment variables available to xedit(1)
## ENVIRONMENT
-
+
* `BASH_ENV`:
- Set to same value as $EDITRCFILE so that the file is loaded as a bash script
+ Set to same value as $EDITRCFILE so that the file is loaded as a bash script
in the event that the user shell is bash(1)
* `DISPLAY`:
- This variable is used to determine if we are running in an X11 environment.
- If $DISPLAY is not set then the contents of the $EDITOR variable is used to
- determine what editor to launch in lieu of xedit(1). If $EDITOR is not set
+ This variable is used to determine if we are running in an X11 environment.
+ If $DISPLAY is not set then the contents of the $EDITOR variable is used to
+ determine what editor to launch in lieu of xedit(1). If $EDITOR is not set
then vim(1) is launched instead.
-
+
* `EDITRCFILE`:
- Contains the path of the shell script which is loaded before xedit(1) to
- setup the environment and define shell functions which can be called during
+ Contains the path of the shell script which is loaded before xedit(1) to
+ setup the environment and define shell functions which can be called during
an editing session.
* `EDITOR`:
- Used as a fallback for when not running in an X11 system (xedit(1) is of
+ Used as a fallback for when not running in an X11 system (xedit(1) is of
course X11 only).
* `PATH`:
- The $PATH variable is modified in order to add $HOME/config/edit/tools/ to
+ The $PATH variable is modified in order to add $HOME/config/edit/tools/ to
the path. This folder is a standard location in which user scripts and tools
can be placed so they can be used from within xedit(1) without cluttering up
the normal system path.
\fBxedit\fR \- a text editor inspired by acme(1) from Plan 9 and Inferno
.
.SH "SYNOPSIS"
-\fBxedit\fR [\fIfile\fR]
+\fBxedit\fR [\fIfile\fR\.\.\.]
.
.SH "DESCRIPTION"
\fBxedit\fR is a text editor inspired by the Acme editor from the Plan 9 and Inferno operating systems\. Unlike Acme, \fBxedit\fR is a single window, single file editor\. Instead of baking a window manager into the editor, this job is relegated to an X11 window manager\. It is recommended that \fBxedit\fR be used with a tiling window manager such as dwm(1) or spectrwm(1)\. These window managers will make dealing with multiple windows much easier and more efficient\.
## SYNOPSIS
-`xedit` [_file_]
+`xedit` [_file_...]
## DESCRIPTION
#!/bin/sh
-# exits with error message
-die() {
- printf "error: %s\n" "$@"
- exit 1
-}
-
-# search for a ctags file recursively up the directory tree from the file to be
-# opened. If one is found, change the working directory of the new process to
-# the containing folder and launch xedit with the path of the file relative to
-# the new working directory.
-edit_relative_ctags(){
- origdir="$PWD"
- case "$1" in
- /*) origpath="$1" ;; # absoulte path given
- *) origpath="$PWD/$1" ;; # relative path given
- esac
- path="${origpath##*/}"
-
- # try to cd to the directory containing the file and attempt to walk the
- # tree backwars until we find a tags file. if one is found, open the file
- # from that directory.
- cd "${origpath%/*}" || die "could not open file: '$1'"
- dir="$PWD"
- while [ "$dir" != "" ]; do
- if [ -f "$dir/tags" ]; then
- cd "$dir" && exec nohup xedit "$path" > /dev/null 2>&1
- else
- path="${dir##*/}/$path"
- dir="${dir%/*}"
- fi
- done
-
- # file is not part of a project. open it as-is
- cd "$origdir" && exec nohup xedit "$1" > /dev/null 2>&1
-}
-
# Add the editing tools directory to your PATH var so its contents may be used
# while editing.
export PATH="$HOME/.config/edit/tools:$PATH"
else
"$EDITOR" "$@"
fi
-elif [ 0 -eq $# ]; then
- (nohup xedit > /dev/null 2>&1) &
else
- for f in "$@"; do
- edit_relative_ctags "$f" &
- done
+ (nohup xedit "$@" > /dev/null 2>&1) &
fi
char* fdgets(int fd);
char* chomp(char* in);
uint64_t modtime(char* path);
+char* getcurrdir(void);
+char* dirname(char* path);
+bool try_chdir(char* fpath);
+char* strconcat(char* dest, ...);
+bool file_exists(char* path);
/* Buffer management functions
*****************************************************************************/
int fd = open(path, O_CREAT|O_RDWR, 0644);
if (fd >= 0) {
ftruncate(fd, sz);
- void* buf = mmap(NULL, pagealign(sz), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (buf != MAP_FAILED) {
+ void* buf = mmap(NULL, pagealign(sz), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (buf != MAP_FAILED) {
file.buf = buf;
file.len = sz;
}
return 0u;
return (uint64_t)status.st_mtime;
}
+
+char* getcurrdir(void) {
+ size_t size = 4096;
+ char *buf = NULL, *ptr = NULL;
+ for (; ptr == NULL; size *= 2) {
+ buf = realloc(buf, size);
+ ptr = getcwd(buf, size);
+ if (ptr == NULL && errno != ERANGE)
+ die("Failed to retrieve current directory");
+ }
+ return buf;
+}
+
+char* dirname(char* path) {
+ path = stringdup(path);
+ char* end = strrchr(path, '/');
+ if (!end) return NULL;
+ *end = '\0';
+ return path;
+}
+
+bool try_chdir(char* fpath) {
+ char* dir = dirname(fpath);
+ bool success = (dir && *dir && chdir(dir) >= 0);
+ free(dir);
+ return success;
+}
+
+char* strconcat(char* dest, ...) {
+ va_list args;
+ char* curr = dest;
+ va_start(args, dest);
+ for (char* s; (s = va_arg(args, char*));)
+ while (*s) *(curr++) = *(s++);
+ va_end(args);
+ *curr = '\0';
+ return dest;
+}
+
+bool file_exists(char* path) {
+ struct stat st;
+ return (stat(path, &st) < 0);
+}
#include <ctype.h>
#include <win.h>
#include <shortcuts.h>
+#include <unistd.h>
#define INCLUDE_DEFS
#include "config.h"
quit();
}
+void edit_relative(char* path) {
+ char *currdir = NULL, *currpath = NULL, *relpath = NULL;
+ char* origdir = getcurrdir();
+
+ /* search for a ctags index file indicating the project root */
+ if (try_chdir(path)) {
+ currdir = getcurrdir();
+ currpath = calloc(strlen(currdir) + strlen("/tags") + 1, 1);
+ relpath = calloc(strlen(currdir) + strlen("/tags") + 1, 1);
+ while (true) {
+ /* figure out the current path to check */
+ strconcat(currpath, currdir, "/tags", 0);
+ if (file_exists(currpath)) {
+ /* move up a dir */
+ char* end = strrchr(currdir,'/');
+ if (!end) break;
+ char* temp = stringdup(relpath);
+ strconcat(relpath, end, temp, 0);
+ free(temp);
+ *end = '\0';
+ } else {
+ break;
+ }
+ }
+ }
+
+ /* cd to the project directory or the original working directory and open
+ the file relative to the new working directory */
+ if (currdir && *currdir) {
+ char* fname = strrchr(path, '/')+1;
+ if (*relpath)
+ strconcat(currpath, relpath+1, "/", fname, 0);
+ else
+ strconcat(currpath, fname, 0);
+ chdir(currdir);
+ view_init(win_view(EDIT), currpath, ondiagmsg);
+ } else {
+ chdir(origdir);
+ view_init(win_view(EDIT), path, ondiagmsg);
+ }
+
+ /* cleanup */
+ free(currdir);
+ free(currpath);
+ free(relpath);
+ free(origdir);
+}
+
#ifndef TEST
int main(int argc, char** argv) {
/* setup the shell */
char* tags = getenv("EDITTAGS");
win_settext(TAGS, (tags ? tags : DefaultTags));
win_setruler(RulePosition);
- view_init(win_view(EDIT), (argc > 1 ? argv[1] : NULL), ondiagmsg);
+ /* open the first file in this instance */
+ if (argc > 1)
+ edit_relative(argv[1]);
+ /* spawn a new instance for each remaining file */
+ for (int i = 2; i < argc; i++) {
+ OpenCmd[1] = argv[i];
+ cmdrun(OpenCmd, NULL);
+ }
+ /* now create the window and start the event loop */
win_setkeys(Bindings);
win_loop();
return 0;