Skip to content

Commit 9e2d79c

Browse files
committed
Add command history
1 parent bdd2b5f commit 9e2d79c

File tree

7 files changed

+245
-15
lines changed

7 files changed

+245
-15
lines changed

Makefile.in

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,22 @@ mandir = $(datarootdir)/man
1212
INSTALL ?= install
1313
INSTALLFLAGS ?=
1414

15-
SRCS=text.c prompt.c cocowm.c layout.c trace.c keyboard.c pane.c action.c \
16-
resize.c column.c event.c create.c manage.c draw.c init.c
15+
SRCS=history.c \
16+
text.c \
17+
prompt.c \
18+
cocowm.c \
19+
layout.c \
20+
trace.c \
21+
keyboard.c \
22+
pane.c \
23+
action.c \
24+
resize.c \
25+
column.c \
26+
event.c \
27+
create.c \
28+
manage.c \
29+
draw.c \
30+
init.c
1731
DISTFILES=\
1832
Makefile\
1933
README\

action.c

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,32 @@ new_command(struct pane *focus, struct layout *l)
167167
close_pane(p, l);
168168
}
169169

170+
void
171+
edit_finish(const char *s, void *udata)
172+
{
173+
struct pane *p = udata;
174+
}
175+
176+
void
177+
edit_step(const char *s, void *udata)
178+
{
179+
struct pane *p = udata;
180+
const char *q;
181+
int col;
182+
183+
TRACE("Edit step: '%s'", s);
184+
185+
q = history_match(s);
186+
if (q != NULL)
187+
snprintf(p->prompt.text, sizeof(p->prompt.text), "%s", q);
188+
}
189+
170190
static int
171191
edit_command(struct pane *p, struct layout *l)
172192
{
173193
p->flags |= PF_EDIT;
174194
draw_frame(p, l);
175-
if (prompt_read(&p->prompt)) {
195+
if (prompt_read(&p->prompt, edit_finish, edit_step, p)) {
176196
p->flags |= PF_WANT_RESTART;
177197
close_pane(p, l);
178198
return 1;
@@ -383,11 +403,7 @@ run_command(struct pane *pane, char *s)
383403
if (snprintf(p, sz, "%s%s", prefix, cmd) >= sz)
384404
assert(0);
385405

386-
#if 0
387-
if (add_command_to_history(q, 1))
388-
save_command_history();
389-
#endif
390-
406+
history_add(q);
391407
free(q);
392408

393409
sh = getenv("SHELL");

cocowm.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ main(int argc, char *argv[])
5252

5353
#ifdef __OpenBSD__
5454
#if 1
55-
if (pledge("stdio rpath proc exec", NULL) == -1)
55+
if (pledge("stdio rpath wpath cpath proc exec", NULL) == -1)
5656
err(1, "pledge");
5757
#else
5858
if (pledge("stdio rpath", NULL) == -1)

draw.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ void
112112
draw_frame(struct pane *p, struct layout *l)
113113
{
114114
char number_str[20];
115-
int x, y;
115+
int x, y, prompt_x;
116116
XftColor bg;
117117

118118
TRACE("try draw frame of %s", PANE_STR(p));
@@ -140,6 +140,7 @@ draw_frame(struct pane *p, struct layout *l)
140140

141141
x += font_draw(p->ftdraw, l->display, p->frame, l->text_fg, bg,
142142
x, x, y, number_str, strlen(number_str));
143+
prompt_x = x;
143144

144145
if (p->flags & PF_EDIT) {
145146
x += font_draw(p->ftdraw, l->display, p->frame, l->text_fg, bg,
@@ -152,9 +153,14 @@ draw_frame(struct pane *p, struct layout *l)
152153
x, x, y, p->icon_name, strlen(p->icon_name));
153154
}
154155

156+
/*
157+
* Draw cursor.
158+
*/
155159
if (p->flags & PF_EDIT) {
160+
prompt_x += ((p->prompt.cursor - p->prompt.text) * l->font_width_px);
156161
x += font_draw(p->ftdraw, l->display, p->frame, l->text_fg,
157-
l->text_cursor, x, x, y, " ", 1);
162+
l->text_cursor, prompt_x, prompt_x, y,
163+
*p->prompt.cursor != '\0' ? p->prompt.cursor : " ", 1);
158164
}
159165

160166
if (p->flags & PF_FULLSCREEN)

extern.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,16 @@ void send_take_focus(struct pane *p, Display *d);
195195
void minimize(struct pane *, struct layout *);
196196
void minimize_others(struct pane *, struct layout *);
197197

198+
typedef void (*PromptCallback)(const char *, void *);
199+
198200
void prompt_insert(struct prompt *, char *);
199201
void prompt_init(struct prompt *, struct pane *, struct layout *);
200-
int prompt_read(struct prompt *);
202+
int prompt_read(struct prompt *, PromptCallback, PromptCallback, void *);
203+
204+
const char *history_match(const char *s);
205+
void history_load();
206+
void history_save();
207+
void history_add(const char *s);
201208

202209
enum action {
203210
NoAction=0,

history.c

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
* cocowm - Column Commander Window Manager for X11 Window System
3+
* Copyright (c) 2023, Tommi Leino <[email protected]>
4+
*
5+
* Permission to use, copy, modify, and/or distribute this software for any
6+
* purpose with or without fee is hereby granted, provided that the above
7+
* copyright notice and this permission notice appear in all copies.
8+
*
9+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16+
*/
17+
18+
#include "extern.h"
19+
20+
#include <err.h>
21+
22+
struct history {
23+
char *line;
24+
struct history *prev;
25+
struct history *next;
26+
};
27+
28+
static struct history *head;
29+
static struct history *tail;
30+
31+
static char *file = ".cocowm_history";
32+
33+
static const char *history_path();
34+
35+
void history_save();
36+
37+
static const char *
38+
history_path()
39+
{
40+
const char *home;
41+
static char s[PATH_MAX];
42+
43+
home = getenv("HOME");
44+
if (home == NULL)
45+
home = "/";
46+
47+
if (snprintf(s, sizeof(s), "%s/%s", home, file) >= sizeof(s))
48+
err(1, "history path name overflow");
49+
50+
return s;
51+
}
52+
53+
const char *
54+
history_match(const char *s)
55+
{
56+
ssize_t i;
57+
size_t best_pts = 0, pts;
58+
const char *best_match = NULL, *p, *q;
59+
struct history *h;
60+
61+
if (s == NULL)
62+
return NULL;
63+
64+
if (head == NULL)
65+
history_load();
66+
67+
for (h = head; h != NULL; h = h->next) {
68+
q = s;
69+
p = h->line;
70+
pts = 0;
71+
while (*p != '\0' && *q != '\0')
72+
if (*p++ == *q++)
73+
pts++;
74+
else {
75+
pts = 0;
76+
break;
77+
}
78+
if (*p == '\0' && *q != '\0')
79+
pts = 0;
80+
if (pts > best_pts) {
81+
best_pts = pts;
82+
best_match = h->line;
83+
}
84+
}
85+
86+
return best_match;
87+
}
88+
89+
void
90+
history_remove(const char *s)
91+
{
92+
struct history *h;
93+
94+
for (h = head; h != NULL; h = h->next)
95+
if (strcmp(h->line, s) == 0)
96+
break;
97+
if (h == NULL)
98+
return;
99+
100+
if (h->prev)
101+
h->prev->next = h->next;
102+
if (h->next)
103+
h->next->prev = h->prev;
104+
if (h == head)
105+
head = h->next;
106+
if (h == tail)
107+
tail = h->prev;
108+
109+
free(h->line);
110+
free(h);
111+
}
112+
113+
void
114+
history_add(const char *s)
115+
{
116+
struct history *h;
117+
118+
history_remove(s);
119+
120+
h = calloc(1, sizeof(*h));
121+
if (h == NULL) {
122+
warn("saving history");
123+
return;
124+
}
125+
126+
h->line = strdup(s);
127+
if (h->line == NULL) {
128+
free(h);
129+
warn("strdup history");
130+
return;
131+
}
132+
133+
h->next = head;
134+
if (h->next != NULL)
135+
h->next->prev = h;
136+
head = h;
137+
if (tail == NULL)
138+
tail = h;
139+
140+
history_save();
141+
}
142+
143+
void
144+
history_load()
145+
{
146+
FILE *fp;
147+
char *line = NULL;
148+
size_t sz = 0;
149+
ssize_t len;
150+
const char *s;
151+
152+
s = history_path();
153+
fp = fopen(s, "r");
154+
if (fp == NULL) {
155+
warnx("fopen history for reading");
156+
return;
157+
}
158+
159+
while ((len = getline(&line, &sz, fp)) > 0) {
160+
line[strcspn(line, "\r\n")] = '\0';
161+
history_add(line);
162+
}
163+
if (ferror(fp))
164+
warnx("getline %s", s);
165+
166+
if (line != NULL)
167+
free(line);
168+
}
169+
170+
void
171+
history_save()
172+
{
173+
FILE *fp;
174+
struct history *h;
175+
const char *s;
176+
177+
s = history_path();
178+
fp = fopen(s, "w");
179+
if (fp == NULL)
180+
err(1, "fopen history for writing");
181+
182+
for (h = tail; h != NULL; h = h->prev)
183+
fprintf(fp, "%s\n", h->line);
184+
185+
if (ferror(fp))
186+
warn("%s", s);
187+
fclose(fp);
188+
}

prompt.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,13 @@ isu8cont(unsigned char c)
5353
void
5454
prompt_insert(struct prompt *p, char *s)
5555
{
56-
TRACE("Insert char %s", s);
5756
while (*s != '\0') {
5857
if (is_full(p))
5958
break;
6059
*(p->cursor)++ = *s++;
6160
}
6261

6362
*p->cursor = '\0';
64-
TRACE("text is now %s", p->text);
6563
}
6664

6765
static int
@@ -100,7 +98,7 @@ prompt_init(struct prompt *p, struct pane *pane, struct layout *layout)
10098
* Read text from the prompt.
10199
*/
102100
int
103-
prompt_read(struct prompt *p)
101+
prompt_read(struct prompt *p, PromptCallback callback, PromptCallback step, void *udata)
104102
{
105103
Display *dpy;
106104
int ret = 1;
@@ -134,6 +132,7 @@ prompt_read(struct prompt *p)
134132
} else
135133
ret = 0;
136134
}
135+
step(p->text, udata);
137136
draw_frame(p->pane, p->pane->column->layout);
138137
break;
139138
case KeyRelease:

0 commit comments

Comments
 (0)