-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgetline.cpp
419 lines (375 loc) · 9.55 KB
/
getline.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#undef CTRL
#define CTRL(x) ((x) & 0x1F)
#include "getline.h"
#include "nnhash.h"
Status (GetLine::*GetLine::which_command(int key))(int key)
{
return (unsigned)key>=numof(bindmap)
? &GetLine::insert
: bindmap[(unsigned)key];
}
Status GetLine::interpret(int key)
{
return (this->*this->which_command(key))(key);
}
/* バッファ上のある範囲を表示する。
* 末尾で倍角文字が分断されるときはダミー文字が表示される。
* from - 表示開始位置(バッファ上での位置)
* to - 表示終了位置(バッファ上での位置)
* [from,to-1]が表示される。
* return
* 表示した文字のバイト数(桁数)
*/
int GetLine::puts_between(int from,int to)
{
if( from < offset ) from = offset;
if( to > offset+width ) to = offset+width;
/* 1文字目 */
if( to-from > 0 )
putchr( buffer.isKnj2(from) ? '^' : buffer[ from ] );
/* 2文字目~n-1文字目 */
for(int i=from+1 ; i < to-1 ; i++)
putchr( buffer[i] );
/* n文字目 */
if( to-from > 1 )
putchr( buffer.isKnj1(to-1) ? '$' : buffer[to-1] );
return to-from <= 0 ? 0 : to-from ;
}
int GetLine::putspc(int n)
{
for(int i=0;i<n;i++)
putchr(' ');
return n;
}
/* カーソル以降を再描画 */
void GetLine::repaint_after(int rm)
{
int bs=puts_between(pos,buffer.length());
while( rm-- > 0 && (pos+bs-offset) < width ){
putchr( ' ' );
++bs;
}
putbs( bs );
}
/* カーソル位置に文字列を挿入し、表示を更新する。
* s - 文字列
* return
* 挿入バイト数
*/
int GetLine::insertHere( const char *s )
{
int n=buffer.insert(s,pos);
if( n <= 0 )
return 0; // memory allocation error.
if( pos+n < offset+width ){
// 挿入文字列の末尾が画面幅に収まる場合、そのまま表示する.
pos += puts_between( pos , pos+n );
repaint_after();
}else{
/* 挿入文字列の末尾が画面幅を超える場合
* 先頭を計算しなおして、全体を表示しなおす。
*/
putbs( pos-offset );
offset = (pos+=n)-width;
puts_between( head() , pos );
}
return n;
}
/* 一行入力メイン関数(1).
* result - [in] 入力のデフォルト値 [out] 入力結果
* return
* 0以上 - 文字列の長さ
* -1 - キャンセルされた
* -2 - その他のエラー
*/
int GetLine::operator() ( NnString &result )
{
if( buffer.init() )
return -2;
pos = offset = 0;
width = DEFAULT_WIDTH ;
history_pointor = history.size();
NnString foo;
history << foo;
start(); /* ← プロンプトが表示される */
/* デフォルト値がある場合 */
if( result.length() > 0 ){
if( buffer.insert( result.chars(),0 ) > 0 ){
// 挿入が成功した場合のみ:
if( (pos=buffer.length()) >= width )
offset = buffer.length()-width;
puts_between( offset , buffer.length() );
}
}
lastKey = 0;
for(;;){
int key=getkey();
int len;
switch( interpret(key) ){
case CONTINUE:
break;
case CANCEL:
buffer.term();
end();
result.erase();
history.drop();
return -1;
case ENTER:
if( buffer.length() > 0 ){
len = buffer.decode( result );
NnString *r=history.top();
if( r != NULL )
*r = result;
history.pack();
}else{
len = 0;
history.drop();
result = "";
}
end();
buffer.term();
return len;
}
lastKey = key;
}
}
void GetLine::replace_all_repaint( const NnString &s )
{
// プロンプト直後にカーソルを戻す.
putbs( pos-offset );
// それまでの表示文字数をカウント.
int clearSize=printedSize();
// 現在のヒストリカーソルの内容を編集内容と置き換える.
buffer.replace( 0,buffer.length(),s.chars() );
pos = buffer.length();
offset = 0;
// 表示幅よりも文字数が大きければ、表示トップをずらす.
if( pos+1 >= width )
offset = pos+1-width;
puts_between( offset , buffer.length() );
int diff = clearSize - printedSize() ;
for( int bs=0 ; bs < diff ; bs++ )
putchr(' ');
putbs(diff);
}
/* 単語を抽出する
* m - 行位置
* n - 語数位置
* word - 検索単語
*/
void GetLine::get_nline_nword(int m,int n,NnString &word)
{
NnString line=*history[m];
NnString left;
line.splitTo( word , left);
for(int i=0 ; i< n ; i++ ){
left.splitTo( word , left );
}
}
/* 行単位でヒストリを検索する
* m - ヒストリ番号
* line - 検索キー
*/
int GetLine::seekLineForward(int &m, const char *line)
{
for(;;){
if( --m < 0 )
return -1;
if( history[m]->startsWith(line) )
return 0;
}
}
/* 行単位でヒストリを検索する
* m - ヒストリ番号
* line - 検索キー
*/
int GetLine::seekLineBackward(int &m, const char *line )
{
for(;;){
if( ++m >= history.size() )
return -1;
if( history[m]->startsWith(line) )
return 0;
}
}
/* 単語を検索する
* m - 行位置
* n - 語数位置
* word - 検索単語
* return
* 0 - 見つかった
* -1 - 見つからなかった
*/
int GetLine::seekWordForward(int &m,int &n,const NnString &word , NnString &found)
{
for(;;){
get_nline_nword(m,++n,found);
if( found.empty() ){ /* 末尾に移動 */
if( --m < 0 )
return -1;
n=0;
}else if( found.startsWith(word) ){
return 0;
}
}
}
static int count_words(const NnString &line)
{
int i=0;
int quote=0;
int nwords=0;
for(;;){
for(;;){
if( i >= line.length() )
return nwords;
if( ! isSpace(line.at(i)) )
break;
++i;
}
++nwords;
for(;;){
if( i >= line.length() )
return nwords;
if( !quote && isSpace(line.at(i)) )
break;
if( line.at(i)=='"')
quote = !quote;
++i;
}
}
}
/* 未来方向へ単語を検索する
* m - 行位置
* n - 語数位置
* word - 検索単語
* return
* 0 - 見つかった
* -1 - 見つからなかった
*/
int GetLine::seekWordBackward(int &m,int &n,const NnString &word,NnString &found)
{
for(;;){
while( --n <= 0 ){
if( ++m >= history.size() )
return -1;
n = count_words(*history[m]);
}
get_nline_nword(m,n,found);
if( found.startsWith(word) )
return 0;
}
}
/* printSeal で表示したシールを消す */
void GetLine::eraseSeal( int sealsize )
{
putbs( sealsize );
if( offset > pos ){
offset = pos;
}
repaint_after(sealsize);
}
/* カーソル位置からシールを表示する。
* シールは repaint_after を実行することで消去できる。
* seal 表示するシール
* sealsize 前回の表示したシールサイズ
* (上書きできなかった部分を空白にする)
* return
* シールサイズ
*/
int GetLine::printSeal( const char *seal , int sealsize )
{
putbs( sealsize );
int seallen = TwinBuffer::strlen_ctrl(seal);
if( width+offset < pos + seallen ){
/* シールを表示する空間がない場合は、
* 左へ適当にスクロールさせる。
* 元々 offset < pos < offset+width < pos + seallen
*/
putbs( pos - offset );
offset = pos + seallen - width;
if( offset < 0 )
offset = 0;
puts_between( offset , pos );
}
int bs=0;
int i=pos;
while( *seal != '\0' ){
if( TwinBuffer::isCtrl(*seal) ){
if( bs+1 >= width || i+1 >= offset+width )
break;
putchr( '^' );
putchr( '@' + *seal++ );
bs += 2;
i += 2;
}else{
if( bs >= width || i >= offset+width)
break;
putchr( *seal++ );
++bs;
++i;
}
}
int bs2=bs;
while( i < offset+width && bs2 < sealsize && bs2 < width ){
putchr( ' ' );
++bs2;
++i;
}
if( bs2 > bs )
putbs( bs2-bs );
return bs;
}
GetLine::~GetLine(){}
int GetLine::prompt(){ return 0;}
/* カーソル上の単語の範囲取得.
* out:
* at - 単語の先頭
* size - 単語の長さ
* return:
* 文字列自身
*/
NnString GetLine::current_word(int &at,int &size)
{
NnString *temp=(NnString *)properties.get("uncompletechar");
const char *dem="";
if( temp != NULL ){
temp->trim();
dem = temp->chars();
}
int inQuote=0;
int j=0;
at = 0;
for(;;){
for(;;){ /* 空白のスキップ */
if( j >= pos ){
/* ここは goto done ではなく、at を変更させるべく、
* break にしておかなくてはいけない */
break;
}
if( ! isSpace(buffer[j] & 255) && strchr(dem,buffer[j] & 255) == NULL )
break;
++j;
}
at = j;
for(;;){
if( j >= pos )
goto done;
if( !inQuote ){
if( isSpace(buffer[j]) || strchr(dem,buffer[j]) != NULL )
break;
}
if( buffer[j] == '"' )
inQuote = !inQuote;
++j;
}
}
done:
size = j - at;
NnString result;
buffer.decode(at,size,result);
return result;
}