1 ////////////////////////////////////////////////////////////////////////////////
2 static char **cmdHistory
= NULL
;
3 static int cmdHistoryCount
= 0;
4 static int cmdHistoryCurrent
= -1; // <0: command line
5 static char cmdLineCur
[K8T_UTF_SIZ
*CMDLINE_SIZE
];
8 static void cmdAddToHistory (const char *cmd
) {
9 if (cmd
== NULL
) return;
10 while (*cmd
&& isspace(*cmd
)) ++cmd
;
12 // check if we already have such command
13 for (int f
= 0; f
< cmdHistoryCount
; ++f
) {
14 if (strcmp(cmdHistory
[f
], cmd
) == 0) {
15 // bingo! move it down
16 char *c
= cmdHistory
[f
];
17 for (int c
= f
; c
< cmdHistoryCount
-1; ++c
) cmdHistory
[c
] = cmdHistory
[c
+1];
18 cmdHistory
[cmdHistoryCount
-1] = c
;
23 if (cmdHistoryCount
< 128) {
24 // allocate memory for new command
26 cmdHistory
= realloc(cmdHistory
, sizeof(char *)*cmdHistoryCount
);
28 // remove top command, add this one
30 for (int f
= 1; f
< cmdHistoryCount
; ++f
) cmdHistory
[f
-1] = cmdHistory
[f
];
32 cmdHistory
[cmdHistoryCount
-1] = strdup(cmd
);
36 ////////////////////////////////////////////////////////////////////////////////
37 static void tcmdlinedirty (K8Term
*term
, K8TCmdLine
*cmdline
) {
40 k8t_tmDirtyMark(term
, term
->row
-term
->topline
-1, 2);
41 k8t_tmWantRedraw(term
, 1);
46 static void tcmdlinefixofs (K8Term
*term
, K8TCmdLine
*cmdline
) {
47 int len
= k8t_UTF8strlen(cmdline
->cmdline
);
48 int ofs
= len
-(term
->col
-1);
50 for (cmdline
->cmdofs
= 0; ofs
> 0; --ofs
) cmdline
->cmdofs
+= k8t_UTF8Size(cmdline
->cmdline
+cmdline
->cmdofs
);
51 tcmdlinedirty(term
, cmdline
);
55 static void tcmdlinehide (K8Term
*term
, K8TCmdLine
*cmdline
) {
56 if (cmdline
->cmdMode
!= K8T_CMDMODE_NONE
&& term
== xw
.paste_term
) k8stx_finish_paste();
57 cmdHistoryCurrent
= -1;
58 cmdline
->cmdMode
= K8T_CMDMODE_NONE
;
59 cmdline
->cmdcurtabc
= NULL
;
60 tcmdlinedirty(term
, cmdline
);
65 static void tcmdlinemsg (K8Term
*term
, K8TCmdLine
*cmdline
, const char *msg
) {
69 cmdHistoryCurrent
= -1;
70 cmdline
->cmdMode
= K8T_CMDMODE_MESSAGE
;
72 cmdline
->cmdtabpos
= -1;
73 cmdline
->cmdcurtabc
= NULL
;
76 int len
= k8t_UTF8Size(msg
);
78 if (len
< 1 || ofs
+len
>= (int)sizeof(cmdline
->cmdline
)-1) break;
79 memcpy(cmdline
->cmdline
+ofs
, msg
, len
);
84 cmdline
->cmdline
[ofs
] = 0;
85 tcmdlinedirty(term
, cmdline
);
90 static __attribute__((format(printf
,3,4))) void tcmdlinemsgf (K8Term
*term
, K8TCmdLine
*cmdline
, const char *fmt
, ...) {
93 int size
= sizeof(buf
)-1;
101 n
= vsnprintf(xbuf
, size
, fmt
, ap
);
103 if (n
> -1 && n
< size
) break;
104 if (n
> -1) size
= n
+1; else size
+= 4096;
105 if (xbuf
== buf
) xbuf
= NULL
;
106 if ((t
= realloc(xbuf
, size
)) == NULL
) { if (xbuf
) free(xbuf
); return; }
109 tcmdlinemsg(term
, cmdline
, xbuf
);
110 if (xbuf
!= buf
) free(xbuf
);
114 static void tcmdlineinitex (K8Term
*term
, K8TCmdLine
*cmdline
, const char *msg
) {
115 if (term
== xw
.paste_term
) k8stx_finish_paste();
116 cmdline
->cmdMode
= K8T_CMDMODE_INPUT
;
118 cmdline
->cmdline
[0] = 0;
119 cmdline
->cmdc
[0] = 0;
121 cmdline
->cmdtabpos
= -1;
122 cmdline
->cmdcurtabc
= NULL
;
123 cmdline
->cmdreslen
= 0;
124 cmdline
->cmdexecfn
= NULL
;
125 if (msg
!= NULL
&& msg
[0]) {
126 strcpy(cmdline
->cmdline
, msg
);
127 cmdline
->cmdreslen
= strlen(cmdline
->cmdline
);
129 tcmdlinefixofs(term
, cmdline
);
133 static void tcmdlineinit (K8Term
*term
, K8TCmdLine
*cmdline
) {
134 tcmdlineinitex(term
, cmdline
, NULL
);
138 static void tcmdlinechoplast (K8Term
*term
, K8TCmdLine
*cmdline
) {
139 if (cmdline
->cmdcl
!= 0) {
142 if ((int)strlen(cmdline
->cmdline
) > cmdline
->cmdreslen
) {
143 k8t_UTF8ChopLast(cmdline
->cmdline
);
146 tcmdlinefixofs(term
, cmdline
);
151 static void tcmdaddchar (K8Term
*term
, K8TCmdLine
*cmdline
, const char *s
) {
152 int len
= k8t_UTF8Size(s
);
154 int slen
= strlen(cmdline
->cmdline
);
155 if (slen
+len
< (int)sizeof(cmdline
->cmdline
)) {
156 memcpy(cmdline
->cmdline
+slen
, s
, len
);
157 cmdline
->cmdline
[slen
+len
] = 0;
158 tcmdlinefixofs(term
, cmdline
);
164 // externally called (from selection processing code)
165 static void tcmdput (K8Term
*term
, K8TCmdLine
*cmdline
, const char *s
, int len
) {
166 cmdHistoryCurrent
= -1;
169 cmdline
->cmdc
[cmdline
->cmdcl
++] = *s
++;
170 cmdline
->cmdc
[cmdline
->cmdcl
] = 0;
171 if ((ok
= k8t_UTF8IsFull(cmdline
->cmdc
, cmdline
->cmdcl
)) != 0 || cmdline
->cmdcl
== K8T_UTF_SIZ
) {
172 if (ok
) tcmdaddchar(term
, cmdline
, cmdline
->cmdc
);
179 ////////////////////////////////////////////////////////////////////////////////
180 static void tcmdlHistoryMove (K8Term
*term
, K8TCmdLine
*cmdline
, int delta
) {
182 if (cmdHistoryCurrent
< 0) {
183 // save current command line
184 snprintf(cmdLineCur
, sizeof(cmdLineCur
), "%s", cmdline
->cmdline
);
185 cmdHistoryCurrent
= (delta
< 0 ? cmdHistoryCount
-1 : 0);
187 cmdHistoryCurrent
+= (delta
< 0 ? -1 : 1);
189 if (cmdHistoryCurrent
< 0 || cmdHistoryCurrent
>= cmdHistoryCount
) {
190 cmdHistoryCurrent
= -1;
191 // restore command line
192 snprintf(cmdline
->cmdline
, sizeof(cmdline
->cmdline
), "%s", cmdLineCur
);
194 snprintf(cmdline
->cmdline
, sizeof(cmdline
->cmdline
), "%s", cmdHistory
[cmdHistoryCurrent
]);
196 tcmdlinefixofs(term
, cmdline
);
201 // return !0 if event was eaten
202 static int tcmdlProcessKeys (K8Term
*term
, K8TCmdLine
*cmdline
, KeySym ksym
, const char *ksbuf
, int ksbuflen
, XKeyEvent
*e
) {
203 int mode
= cmdline
->cmdMode
;
206 if (cmdline
->cmdline
[0] && !(e
->state
&(Mod1Mask
|ShiftMask
)) && (e
->state
&ControlMask
)) {
208 if (lastSelStr
!= NULL
) free(lastSelStr
);
209 lastSelStr
= strdup(cmdline
->cmdline
);
214 tcmdlinehide(term
, cmdline
);
215 if (cmdline
->cmdexecfn
!= NULL
) {
216 cmdline
->cmdexecfn(term
, cmdline
, 0);
217 } else if (mode
== K8T_CMDMODE_INPUT
) {
218 cmdAddToHistory(cmdline
->cmdline
);
219 executeCommands(cmdline
->cmdline
);
223 if (mode
== K8T_CMDMODE_INPUT
) {
224 cmdHistoryCurrent
= -1;
225 tcmdlinechoplast(term
, cmdline
);
226 cmdline
->cmdtabpos
= -1;
227 cmdline
->cmdcurtabc
= NULL
;
229 tcmdlinehide(term
, cmdline
);
230 if (cmdline
->cmdexecfn
!= NULL
) cmdline
->cmdexecfn(term
, cmdline
, 1);
234 tcmdlinehide(term
, cmdline
);
235 if (cmdline
->cmdexecfn
!= NULL
) cmdline
->cmdexecfn(term
, cmdline
, 1);
238 if (mode
== K8T_CMDMODE_INPUT
&& cmdline
->cmdline
[0] && cmdline
->cmdcl
== 0 && cmdline
->cmdexecfn
== NULL
) {
240 cmdHistoryCurrent
= -1;
241 if (cmdline
->cmdtabpos
< 0) {
242 cmdline
->cmdtabpos
= 0;
243 while (cmdline
->cmdline
[cmdline
->cmdtabpos
] && isalnum(cmdline
->cmdline
[cmdline
->cmdtabpos
])) ++cmdline
->cmdtabpos
;
244 if (cmdline
->cmdline
[cmdline
->cmdtabpos
]) {
245 cmdline
->cmdtabpos
= -1;
248 cmdline
->cmdcurtabc
= NULL
;
250 cpl
= findCommandCompletion(cmdline
->cmdline
, cmdline
->cmdtabpos
, cmdline
->cmdcurtabc
);
251 if (cpl
== NULL
&& cmdline
->cmdcurtabc
!= NULL
) cpl
= findCommandCompletion(cmdline
->cmdline
, cmdline
->cmdtabpos
, NULL
);
252 cmdline
->cmdcurtabc
= cpl
;
253 if (cpl
!= NULL
) { strcpy(cmdline
->cmdline
, cpl
); tcmdaddchar(term
, cmdline
, " "); }
254 tcmdlinefixofs(term
, cmdline
);
255 } else if (mode
!= K8T_CMDMODE_INPUT
) {
256 tcmdlinehide(term
, cmdline
);
257 if (cmdline
->cmdexecfn
!= NULL
) cmdline
->cmdexecfn(term
, cmdline
, 1);
260 case XK_Up
: case XK_KP_8
:
261 if (mode
== K8T_CMDMODE_INPUT
&& cmdline
->cmdexecfn
== NULL
) tcmdlHistoryMove(term
, cmdline
, -1);
263 case XK_Down
: case XK_KP_2
:
264 if (mode
== K8T_CMDMODE_INPUT
&& cmdline
->cmdexecfn
== NULL
) tcmdlHistoryMove(term
, cmdline
, 1);
267 if (mode
!= K8T_CMDMODE_INPUT
) {
268 tcmdlinehide(term
, cmdline
);
273 if (mode
== K8T_CMDMODE_INPUT
) {
274 if (ksbuflen
> 0 && (unsigned char)ksbuf
[0] >= 32) {
275 cmdHistoryCurrent
= -1;
276 tcmdput(term
, cmdline
, ksbuf
, ksbuflen
);
277 cmdline
->cmdtabpos
= -1;
278 cmdline
->cmdcurtabc
= NULL
;
284 return 1; // eat any event