This repository has been archived on 2023-07-11. You can view files and clone it, but cannot push or open issues or pull requests.
fte/i_complete.cpp

414 lines
9.2 KiB
C++

/* i_complete.cpp
*
* Copyright (c) 1998, Zdenek Kabelac
*
* You may distribute under the terms of either the GNU General Public
* License or the Artistic License, as specified in the README file.
*
*/
#include "fte.h"
#ifdef CONFIG_I_COMPLETE
#define STRCOMPLETE "Complete Word: ["
#define STRNOCOMPLETE "No word for completition..."
#define LOCALE_SORT
#ifdef LOCALE_SORT
#if defined(__IBMCPP__)
static int _LNK_CONV CmpStr(const void *p1, const void *p2) {
#else
static int CmpStr(const void *p1, const void *p2) {
#endif
//printf("%s %s %d\n", *(char **)p1, *(char **)p2,
// strcoll(*(char **)p1, *(char **)p2));
return strcoll(*(char **)p1, *(char **)p2);
}
#endif
/**
* Create Sorted list of possible word extensions
*/
ExComplete::ExComplete(EBuffer *B): ExView()
{
Buffer = B;
Orig = Buffer->CP;
WordBegin = NULL;
WordFixed = WordPos = WordsLast = 0;
Words = new char *[MAXCOMPLETEWORDS + 2];
if (Words != NULL)
RefreshComplete();
}
ExComplete::~ExComplete()
{
// fprintf(stderr, "W %p %p %p %d\n", Words, WordContinue, WordBegin, WordsLast);
if (WordBegin != NULL)
delete WordBegin;
if (Words != NULL) {
for(int i = 0; i < WordsLast; i++)
delete Words[i];
delete Words;
}
}
void ExComplete::Activate(int gotfocus)
{
ExView::Activate(gotfocus);
}
int ExComplete::BeginMacro()
{
return 1;
}
void ExComplete::HandleEvent(TEvent &Event)
{
unsigned long kb = kbCode(Event.Key.Code);
int DoQuit = 0;
int i = 0;
if (WordsLast < 2) {
if ((WordsLast == 1) && (kb != kbEsc)) {
DoQuit = 1;
} else {
EndExec(0);
Event.What = evNone;
}
} else if (Event.What == evKeyDown) {
switch(kb) {
case kbPgUp:
case kbLeft:
// if there would not be locale sort, we could check only
// the next string, but with `locale sort` this is impossible!!
// this loop is little inefficient but it's quite short & nice
for (i = WordPos; i-- > 0;)
if (strncmp(Words[WordPos], Words[i], WordFixed) == 0) {
WordPos = i;
break;
}
Event.What = evNone;
break;
case kbPgDn:
case kbRight:
for(i = WordPos; i++ < WordsLast - 1;)
if (strncmp(Words[WordPos], Words[i], WordFixed) == 0) {
WordPos = i;
break;
}
Event.What = evNone;
break;
case kbHome:
for (i = 0; i < WordPos; i++)
if (strncmp(Words[WordPos], Words[i], WordFixed) == 0)
WordPos = i;
Event.What = evNone;
break;
case kbEnd:
for (i = WordsLast - 1; i > WordPos; i--)
if (strncmp(Words[WordPos], Words[i], WordFixed) == 0)
WordPos = i;
Event.What = evNone;
break;
case kbTab:
while (WordPos < WordsLast - 1) {
WordPos++;
if (strncmp(Words[WordPos], Words[WordPos - 1],
WordFixed + 1))
break;
}
Event.What = evNone;
break;
case kbTab | kfShift:
while (WordPos > 0) {
WordPos--;
if (strncmp(Words[WordPos], Words[WordPos + 1],
WordFixed + 1))
break;
}
Event.What = evNone;
break;
case kbIns:
case kbUp:
FixedUpdate(1);
Event.What = evNone;
break;
case kbBackSp:
case kbDel:
case kbDown:
FixedUpdate(-1);
Event.What = evNone;
break;
case kbEsc:
EndExec(0);
Event.What = evNone;
break;
case kbEnter:
case kbSpace:
case kbTab | kfCtrl:
DoQuit = 1;
break;
default:
if (CheckASCII(Event.Key.Code)) {
char *s = new char[WordFixed + 2];
if (s != NULL) {
if (WordFixed > 0)
strncpy(s, Words[WordPos], WordFixed);
s[WordFixed] = (unsigned char)(Event.Key.Code & 0xFF);
s[WordFixed + 1] = 0;
for (int i = 0; i < WordsLast; i++)
if (strncmp(s, Words[i], WordFixed + 1) == 0) {
WordPos = i;
if (WordFixedCount == 1)
DoQuit = 1;
else
FixedUpdate(1);
break;
}
delete s;
}
Event.What = evNone;
}
break;
}
}
if (DoQuit) {
int rc = 0;
int l = strlen(Words[WordPos]);
if (Buffer->InsText(Buffer->VToR(Orig.Row), Orig.Col, l, Words[WordPos], 1)
&& Buffer->SetPos(Orig.Col + l, Orig.Row)) {
Buffer->Draw(Buffer->VToR(Orig.Row), Buffer->VToR(Orig.Row));
rc = 1;
}
EndExec(rc);
Event.What = evNone;
}
}
void ExComplete::UpdateView()
{
if (Next) {
Next->UpdateView();
}
}
void ExComplete::RepaintView()
{
if (Next) {
Next->RepaintView();
}
}
void ExComplete::UpdateStatus()
{
RepaintStatus();
}
void ExComplete::RepaintStatus()
{
TDrawBuffer B;
int W, H;
// Currently use this fixed colors - maybe there are some better defines??
#define COM_NORM 0x17
#define COM_ORIG 0x1C
#define COM_HIGH 0x1E
#define COM_MARK 0x2E
#define COM_ERR 0x1C
ConQuerySize(&W, &H);
MoveCh(B, ' ', COM_NORM, W);
if ((WordsLast > 0) && (WordBegin != NULL) && (Words != NULL)
&& (Words[WordPos]) != NULL) {
const char *sc = STRCOMPLETE;
int p = sizeof(STRCOMPLETE) - 1;
if (W < 35) {
// if the width is quite small
sc += p - 1; // jump to last character
p = 1;
}
MoveStr(B, 0, W, sc, COM_NORM, W);
// int cur = p;
MoveStr(B, p, W, WordBegin, COM_ORIG, W);
p += strlen(WordBegin);
int l = strlen(Words[WordPos]);
if (WordFixed > 0) {
MoveStr(B, p, W, Words[WordPos], COM_MARK, W);
p += WordFixed;
l -= WordFixed;
}
MoveStr(B, p, W, Words[WordPos] + WordFixed,
(WordFixedCount == 1) ? COM_ORIG : COM_HIGH, W);
p += l;
char s[100];
sprintf(s, "] (T:%d/%d S:%d)", WordPos + 1, WordsLast,
WordFixedCount);
MoveStr(B, p, W, s, COM_NORM, W);
// ConSetCursorPos(cur + WordFixed, H - 1);
} else
MoveStr(B, 0, W, STRNOCOMPLETE, COM_ERR, W);
ConPutBox(0, H - 1, W, 1, B);
ConShowCursor();
}
int ExComplete::RefreshComplete()
{
if ((Buffer->CP.Col == 0)
|| (Buffer->SetPos(Buffer->CP.Col, Buffer->CP.Row) == 0))
return 0;
PELine L = Buffer->VLine(Buffer->CP.Row);
int C = Buffer->CP.Col;
int P = Buffer->CharOffset(L, C);
if (!P || P > L->Count)
return 0;
int P1 = P;
while ((P > 0) && CheckASCII(L->Chars[P - 1]))
P--;
int wlen = P1 - P;
if (!wlen)
return 0;
WordBegin = new char[wlen + 1];
if (WordBegin == NULL)
return 0;
strncpy(WordBegin, L->Chars + P, wlen);
WordBegin[wlen] = 0;
// fprintf(stderr, "Calling %d %s\n", wlen, WordBegin);
// Search words in TAGS
TagComplete(Words, &WordsLast, MAXCOMPLETEWORDS, WordBegin);
// fprintf(stderr, "Located %d words\n", WordsLast);
// these words are already sorted
// Search words in current TEXT
Buffer->Match.Col = Buffer->Match.Row = 0;
// this might look strange but it is necessary to catch
// the first word at position 0,0 for match :-)
unsigned long mask = SEARCH_NOPOS | SEARCH_WORDBEG;
while (Buffer->FindStr(L->Chars + P, wlen, mask) == 1) {
mask |= SEARCH_NEXT;
PELine M = Buffer->RLine(Buffer->Match.Row);
int X = Buffer->CharOffset(M, Buffer->Match.Col);
if ((L->Chars == M->Chars) && (P == X))
continue;
int XL = X;
while ((XL < M->Count) && CheckASCII(M->Chars[XL]))
XL++;
int len = XL - X - wlen;
if (len == 0)
continue;
char *s = new char[len + 1];
if (s != NULL) {
strncpy(s, M->Chars + X + wlen, len);
s[len] = 0;
int c = 1, H = 0, L = 0, R = WordsLast;
// using sort to insert only unique words
while (L < R) {
H = (L + R) / 2;
c = strcmp(s, Words[H]);
if (c < 0)
R = H;
else if (c > 0)
L = H + 1;
else
break;
}
if (c != 0) {
// Loop exited without finding the word. Instead,
// it found the spot where the new should be inserted.
WordsLast++;
int i = WordsLast;
while (i > L) {
Words[i] = Words[i-1];
i--;
}
Words[i] = s;
if (WordsLast >= MAXCOMPLETEWORDS)
break;
} else
{
// word was already listed, free duplicate.
delete s;
}
}
}
Buffer->Match.Row = Buffer->Match.Col = -1;
Buffer->MatchLen = Buffer->MatchCount = 0;
#ifdef LOCALE_SORT
// sort by current locales
qsort(Words, WordsLast, sizeof(Words[0]), CmpStr);
#endif
FixedUpdate(0);
//for(int i = 0; i < WordsLast; i++)
//if (Words[i])
//fprintf(stderr, "%3d:\t%10p\t%s\n", i, Words[i], Words[i]);
//fprintf(stderr, "Words %3d\n", WordsLast);
return WordsLast;
}
void ExComplete::FixedUpdate(int add)
{
if (add < 0) {
if (WordFixed > 0)
WordFixed += add;
} else if (add > 0) {
if (strlen(Words[WordPos]) > WordFixed)
WordFixed += add;
}
if (WordFixed > 0) {
WordFixedCount = 0;
for(int i = 0; i < WordsLast; i++)
if (strncmp(Words[WordPos], Words[i], WordFixed) == 0)
WordFixedCount++;
} else
WordFixedCount = WordsLast;
}
/*
// Well this was my first idea - but these menus are unusable
int menu = NewMenu("CW");
int n;
n = NewItem(menu, "Word1");
Menus[menu].Items[n].Cmd = ExFind;
n = NewItem(menu, "Word2");
Menus[menu].Items[n].Cmd = ExMoveLineStart;
n = NewItem(menu, "Word3");
Menus[menu].Items[n].Cmd = ExMovePageEnd;
printf(">%d ****\n", View->MView->Win->Parent->PopupMenu("CW"));
*/
#endif