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
) {
39 k8t_tmDirtyMark(term
, term
->row
-term
->topline
-1, 2);
40 k8t_tmWantRedraw(term
, 1);
45 static void tcmdlinefixofs (K8Term
*term
, K8TCmdLine
*cmdline
) {
46 int len
= k8t_UTF8strlen(cmdline
->cmdline
);
47 int ofs
= len
-(term
->col
-1);
49 for (cmdline
->cmdofs
= 0; ofs
> 0; --ofs
) cmdline
->cmdofs
+= k8t_UTF8Size(cmdline
->cmdline
+cmdline
->cmdofs
);
50 tcmdlinedirty(term
, cmdline
);
54 static void tcmdlinehide (K8Term
*term
, K8TCmdLine
*cmdline
) {
55 cmdHistoryCurrent
= -1;
56 cmdline
->cmdMode
= K8T_CMDMODE_NONE
;
57 cmdline
->cmdcurtabc
= NULL
;
58 tcmdlinedirty(term
, cmdline
);
63 static void tcmdlinemsg (K8Term
*term
, K8TCmdLine
*cmdline
, const char *msg
) {
67 cmdHistoryCurrent
= -1;
68 cmdline
->cmdMode
= K8T_CMDMODE_MESSAGE
;
70 cmdline
->cmdtabpos
= -1;
71 cmdline
->cmdcurtabc
= NULL
;
74 int len
= k8t_UTF8Size(msg
);
76 if (len
< 1 || ofs
+len
>= sizeof(cmdline
->cmdline
)-1) break;
77 memcpy(cmdline
->cmdline
+ofs
, msg
, len
);
82 cmdline
->cmdline
[ofs
] = 0;
83 tcmdlinedirty(term
, cmdline
);
88 static __attribute__((format(printf
,3,4))) void tcmdlinemsgf (K8Term
*term
, K8TCmdLine
*cmdline
, const char *fmt
, ...) {
91 int size
= sizeof(buf
)-1;
99 n
= vsnprintf(xbuf
, size
, fmt
, ap
);
101 if (n
> -1 && n
< size
) break;
102 if (n
> -1) size
= n
+1; else size
+= 4096;
103 if (xbuf
== buf
) xbuf
= NULL
;
104 if ((t
= realloc(xbuf
, size
)) == NULL
) { if (xbuf
) free(xbuf
); return; }
107 tcmdlinemsg(term
, cmdline
, xbuf
);
108 if (xbuf
!= buf
) free(xbuf
);
112 static void tcmdlineinitex (K8Term
*term
, K8TCmdLine
*cmdline
, const char *msg
) {
113 cmdline
->cmdMode
= K8T_CMDMODE_INPUT
;
115 cmdline
->cmdline
[0] = 0;
116 cmdline
->cmdc
[0] = 0;
118 cmdline
->cmdtabpos
= -1;
119 cmdline
->cmdcurtabc
= NULL
;
120 cmdline
->cmdreslen
= 0;
121 cmdline
->cmdexecfn
= NULL
;
122 if (msg
!= NULL
&& msg
[0]) {
123 strcpy(cmdline
->cmdline
, msg
);
124 cmdline
->cmdreslen
= strlen(cmdline
->cmdline
);
126 tcmdlinefixofs(term
, cmdline
);
130 static void tcmdlineinit (K8Term
*term
, K8TCmdLine
*cmdline
) {
131 tcmdlineinitex(term
, cmdline
, NULL
);
135 static void tcmdlinechoplast (K8Term
*term
, K8TCmdLine
*cmdline
) {
136 if (cmdline
->cmdcl
!= 0) {
139 if (strlen(cmdline
->cmdline
) > cmdline
->cmdreslen
) k8t_UTF8ChopLast(cmdline
->cmdline
);
141 tcmdlinefixofs(term
, cmdline
);
146 static void tcmdaddchar (K8Term
*term
, K8TCmdLine
*cmdline
, const char *s
) {
147 int len
= k8t_UTF8Size(s
);
149 int slen
= strlen(cmdline
->cmdline
);
150 if (slen
+len
< sizeof(cmdline
->cmdline
)) {
151 memcpy(cmdline
->cmdline
+slen
, s
, len
);
152 cmdline
->cmdline
[slen
+len
] = 0;
153 tcmdlinefixofs(term
, cmdline
);
159 // externally called (from selection processing code)
160 static void tcmdput (K8Term
*term
, K8TCmdLine
*cmdline
, const char *s
, int len
) {
161 cmdHistoryCurrent
= -1;
164 cmdline
->cmdc
[cmdline
->cmdcl
++] = *s
++;
165 cmdline
->cmdc
[cmdline
->cmdcl
] = 0;
166 if ((ok
= k8t_UTF8IsFull(cmdline
->cmdc
, cmdline
->cmdcl
)) != 0 || cmdline
->cmdcl
== K8T_UTF_SIZ
) {
167 if (ok
) tcmdaddchar(term
, cmdline
, cmdline
->cmdc
);
174 ////////////////////////////////////////////////////////////////////////////////
175 static void tcmdlHistoryMove (K8Term
*term
, K8TCmdLine
*cmdline
, int delta
) {
177 if (cmdHistoryCurrent
< 0) {
178 // save current command line
179 snprintf(cmdLineCur
, sizeof(cmdLineCur
), "%s", cmdline
->cmdline
);
180 cmdHistoryCurrent
= (delta
< 0 ? cmdHistoryCount
-1 : 0);
182 cmdHistoryCurrent
+= (delta
< 0 ? -1 : 1);
184 if (cmdHistoryCurrent
< 0 || cmdHistoryCurrent
>= cmdHistoryCount
) {
185 cmdHistoryCurrent
= -1;
186 // restore command line
187 snprintf(cmdline
->cmdline
, sizeof(cmdline
->cmdline
), "%s", cmdLineCur
);
189 snprintf(cmdline
->cmdline
, sizeof(cmdline
->cmdline
), "%s", cmdHistory
[cmdHistoryCurrent
]);
191 tcmdlinefixofs(term
, cmdline
);
196 // return !0 if event was eaten
197 static int tcmdlProcessKeys (K8Term
*term
, K8TCmdLine
*cmdline
, KeySym ksym
, const char *ksbuf
, int ksbuflen
, XKeyEvent
*e
) {
198 int mode
= cmdline
->cmdMode
;
201 if (cmdline
->cmdline
[0] && !(e
->state
&(Mod1Mask
|ShiftMask
)) && (e
->state
&ControlMask
)) {
203 if (lastSelStr
!= NULL
) free(lastSelStr
);
204 lastSelStr
= strdup(cmdline
->cmdline
);
209 tcmdlinehide(term
, cmdline
);
210 if (cmdline
->cmdexecfn
!= NULL
) {
211 cmdline
->cmdexecfn(term
, cmdline
, 0);
212 } else if (mode
== K8T_CMDMODE_INPUT
) {
213 cmdAddToHistory(cmdline
->cmdline
);
214 executeCommands(cmdline
->cmdline
);
218 if (mode
== K8T_CMDMODE_INPUT
) {
219 cmdHistoryCurrent
= -1;
220 tcmdlinechoplast(term
, cmdline
);
221 cmdline
->cmdtabpos
= -1;
222 cmdline
->cmdcurtabc
= NULL
;
224 tcmdlinehide(term
, cmdline
);
225 if (cmdline
->cmdexecfn
!= NULL
) cmdline
->cmdexecfn(term
, cmdline
, 1);
229 tcmdlinehide(term
, cmdline
);
230 if (cmdline
->cmdexecfn
!= NULL
) cmdline
->cmdexecfn(term
, cmdline
, 1);
233 if (mode
== K8T_CMDMODE_INPUT
&& cmdline
->cmdline
[0] && cmdline
->cmdcl
== 0 && cmdline
->cmdexecfn
== NULL
) {
235 cmdHistoryCurrent
= -1;
236 if (cmdline
->cmdtabpos
< 0) {
237 cmdline
->cmdtabpos
= 0;
238 while (cmdline
->cmdline
[cmdline
->cmdtabpos
] && isalnum(cmdline
->cmdline
[cmdline
->cmdtabpos
])) ++cmdline
->cmdtabpos
;
239 if (cmdline
->cmdline
[cmdline
->cmdtabpos
]) {
240 cmdline
->cmdtabpos
= -1;
243 cmdline
->cmdcurtabc
= NULL
;
245 cpl
= findCommandCompletion(cmdline
->cmdline
, cmdline
->cmdtabpos
, cmdline
->cmdcurtabc
);
246 if (cpl
== NULL
&& cmdline
->cmdcurtabc
!= NULL
) cpl
= findCommandCompletion(cmdline
->cmdline
, cmdline
->cmdtabpos
, NULL
);
247 cmdline
->cmdcurtabc
= cpl
;
248 if (cpl
!= NULL
) { strcpy(cmdline
->cmdline
, cpl
); tcmdaddchar(term
, cmdline
, " "); }
249 tcmdlinefixofs(term
, cmdline
);
250 } else if (mode
!= K8T_CMDMODE_INPUT
) {
251 tcmdlinehide(term
, cmdline
);
252 if (cmdline
->cmdexecfn
!= NULL
) cmdline
->cmdexecfn(term
, cmdline
, 1);
255 case XK_Up
: case XK_KP_8
:
256 if (mode
== K8T_CMDMODE_INPUT
&& cmdline
->cmdexecfn
== NULL
) tcmdlHistoryMove(term
, cmdline
, -1);
258 case XK_Down
: case XK_KP_2
:
259 if (mode
== K8T_CMDMODE_INPUT
&& cmdline
->cmdexecfn
== NULL
) tcmdlHistoryMove(term
, cmdline
, 1);
262 if (mode
!= K8T_CMDMODE_INPUT
) {
263 tcmdlinehide(term
, cmdline
);
268 if (mode
== K8T_CMDMODE_INPUT
) {
269 if (ksbuflen
> 0 && (unsigned char)ksbuf
[0] >= 32) {
270 cmdHistoryCurrent
= -1;
271 tcmdput(term
, cmdline
, ksbuf
, ksbuflen
);
272 cmdline
->cmdtabpos
= -1;
273 cmdline
->cmdcurtabc
= NULL
;
279 return 1; // eat any event