From: boca4711 <boc...@us...> - 2005-10-16 12:23:41
|
Update of /cvsroot/anyedit/AnyEditv2 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22874 Modified Files: ScintillaEx.cpp ScintillaEx.h Log Message: - Added calltip handling with API files - Added GetLineText to get complete line as string - Added autocompletion handling - Added matching and highlighting of " and ' - Added smart tab and smart insert Index: ScintillaEx.cpp =================================================================== RCS file: /cvsroot/anyedit/AnyEditv2/ScintillaEx.cpp,v retrieving revision 1.26 retrieving revision 1.27 diff -C2 -d -r1.26 -r1.27 *** ScintillaEx.cpp 12 Oct 2005 18:55:57 -0000 1.26 --- ScintillaEx.cpp 16 Oct 2005 12:23:22 -0000 1.27 *************** *** 50,53 **** --- 50,71 ---- m_bSaveConvertTabToSpaces = false; m_bSaveTrimTrailingSpaces = false; + m_lastPosCallTip = 0; + m_Api = NULL; + m_nMaxCallTips = 1; + m_nCurrentCallTip = 0; + m_nStartCalltipWord = 0; + m_nBraceCount = 0; + + m_bCallTipIgnoreCase = true; + m_calltipParametersStart = "("; + m_calltipParametersEnd = ")"; + m_calltipParametersSeparators = ",;"; + m_calltipWordCharacters = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + m_bAutoCompleteIgnoreCase = true; + m_autoCompleteStartCharacters = "."; + + m_bSmartInsert = false; + m_bSmartTab = false; } *************** *** 218,221 **** --- 236,249 ---- } + /// Contains string s char ch? + static bool contains(const char *s, char ch) { + return (s && *s) ? strchr(s, ch) != 0 : false; + } + + // Should also use word.characters.*, if exists, in the opposite way (in set instead of not in set) + static bool iswordcharforsel(char ch) { + return !strchr("\t\n\r !\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", ch); + } + /// Handles notifications from scintilla control. int CScintillaEx::HandleNotify(LPARAM lParam) *************** *** 235,247 **** HighlightBraces(GetCurrentPos() - 1); else ! BraceHighlight(-1, -1); */ case SCN_CHARADDED: ! if (((scn->ch == '\r') || (scn->ch == '\n')) && (GetAutoIndent() >= 1)) ! AutoIndentIn(scn->ch); ! else if ((scn->ch == '{') && (GetAutoIndent() >= 2)) ! AutoIndentOut(scn->ch); ! else if ((scn->ch == '}') && (GetAutoIndent() >= 2)) ! AutoIndentOut(scn->ch); break; case SCN_MODIFIED: --- 263,356 ---- HighlightBraces(GetCurrentPos() - 1); else ! BraceHighlight(INVALID_POSITION, INVALID_POSITION); */ case SCN_CHARADDED: ! { ! if (m_bSmartInsert) ! { ! if (strchr("({[\"\'", scn->ch) != 0 ! && isspace(GetCharAt(GetCurrentPos() + 1))) ! { ! char ch = '\0'; ! switch (scn->ch) ! { ! case '(': ! ch = ')'; ! break; ! case '[': ! ch = ']'; ! break; ! case '{': ! ch = '}'; ! break; ! case '\"': ! ch = '\"'; ! break; ! case '\'': ! ch = '\''; ! break; ! default: ! break; ! } ! if (ch) ! { ! InsertChar(GetCurrentPos(), ch); ! } ! } ! } ! CharacterRange crange = GetSelection(); ! int selStart = crange.cpMin; ! int selEnd = crange.cpMax; ! if ((selEnd == selStart) && (selStart > 0)) { ! int style = GetStyleAt(selStart - 1); ! //Platform::DebugPrintf("Char added %d style = %d %d\n", scn->ch, style, braceCount); ! if (style != 1) { ! if (CallTipActive()) { ! if (contains(m_calltipParametersEnd, scn->ch)) { ! m_nBraceCount--; ! if (m_nBraceCount < 1) ! CallTipCancel(); ! else ! StartCallTip(); ! } else if (contains(m_calltipParametersStart, scn->ch)) { ! m_nBraceCount++; ! StartCallTip(); ! } else { ! ContinueCallTip(); ! } ! } else if (AutoCActive()) { ! if (contains(m_calltipParametersStart, scn->ch)) { ! m_nBraceCount++; ! StartCallTip(); ! } else if (contains(m_calltipParametersEnd, scn->ch)) { ! m_nBraceCount--; ! } else if (!contains(m_strWordCharacters, scn->ch)) { ! AutoCCancel(); ! if (contains(m_autoCompleteStartCharacters, scn->ch)) { ! StartAutoComplete(); ! } ! /* } else if (autoCCausedByOnlyOne) { ! StartAutoCompleteWord(true); ! */ ! } ! } else { ! if (contains(m_calltipParametersStart, scn->ch)) { ! m_nBraceCount = 1; ! StartCallTip(); ! } else { ! if (((scn->ch == '\r') || (scn->ch == '\n')) && (GetAutoIndent() >= 1)) ! AutoIndentIn(scn->ch); ! else if ((scn->ch == '{') && (GetAutoIndent() >= 2)) ! AutoIndentOut(scn->ch); ! else if ((scn->ch == '}') && (GetAutoIndent() >= 2)) ! AutoIndentOut(scn->ch); ! if (contains(m_autoCompleteStartCharacters, scn->ch)) { ! StartAutoComplete(); ! } ! } ! } ! } ! } ! } break; case SCN_MODIFIED: *************** *** 252,255 **** --- 361,395 ---- SetLineNumberWidth(); break; + case SCN_CALLTIPCLICK: + if (scn->position == 1 && m_nCurrentCallTip > 0) + { + m_nCurrentCallTip--; + FillFunctionDefinition(); + } else if (scn->position == 0 && m_nCurrentCallTip + 1 < m_nMaxCallTips) { + m_nCurrentCallTip++; + FillFunctionDefinition(); + } + break; + case SCN_DWELLSTART: + { + if (INVALID_POSITION == scn->position) { + char message[200]; + sprintf(message, "%0d (%0d,%0d)", scn->position, scn->x, scn->y); + } else { + int selStart = scn->position; + int selEnd = scn->position; + char sel[200]; + RangeExtendAndGrab(sel, 200, selStart, selEnd, GetLength(), iswordcharforsel); + if (*sel) { + CallTipShow(scn->position, sel); + } + } + } + break; + + case SCN_DWELLEND: + CallTipCancel(); + break; + } return scn->nmhdr.code; *************** *** 2014,2015 **** --- 2154,2832 ---- return _T(""); } + + void CScintillaEx::FillFunctionDefinition(int pos) + { + if (pos > 0) + { + m_lastPosCallTip = pos; + } + if (m_Api && m_Api->GetSize() > 0) + { + CString words = GetNearestWords(m_Api, m_currentCallTipWord, strlen(m_currentCallTipWord), + m_bCallTipIgnoreCase, m_calltipParametersStart[0], true); + if (words.IsEmpty()) + return; + // Counts how many call tips + const char *spacePos = strchr(words, ' '); + m_nMaxCallTips = 1; + while (spacePos) { + m_nMaxCallTips++; + spacePos = strchr(spacePos + 1, ' '); + } + + // Should get current api definition + const char *word = GetNearestWord(m_Api, m_currentCallTipWord, strlen(m_currentCallTipWord), + m_bCallTipIgnoreCase, m_calltipWordCharacters, m_nCurrentCallTip); + if (word) { + m_functionDefinition = word; + if (m_nMaxCallTips > 1) { + m_functionDefinition.Insert(0, "\001"); + } + + if (! m_calltipEndDefinition.IsEmpty()) { + int posEndDef = m_functionDefinition.Find(m_calltipEndDefinition); + if (m_nMaxCallTips > 1) { + if ((posEndDef > 1) && + ((posEndDef + m_calltipEndDefinition.GetLength()) < m_functionDefinition.GetLength())) { + m_functionDefinition.Insert(posEndDef + m_calltipEndDefinition.GetLength(), "\n\002"); + } else { + m_functionDefinition + "\n\002"; + } + } else { + if ((posEndDef > 1) && + ((posEndDef + m_calltipEndDefinition.GetLength()) < m_functionDefinition.GetLength())) { + m_functionDefinition.Insert(posEndDef + m_calltipEndDefinition.GetLength(), "\n"); + } + } + } + CallTipShow(m_lastPosCallTip - strlen(m_currentCallTipWord), m_functionDefinition); + ContinueCallTip(); + } + } + } + + bool CScintillaEx::StartCallTip() + { + m_nCurrentCallTip = 0; + m_currentCallTipWord.Empty(); + CString strLine = GetLineText(); + int current = GetCaretInLine(); + int pos = GetCurrentPos(); + int braces; + do { + braces = 0; + while (current > 0 && (braces || !contains(m_calltipParametersStart, strLine[current - 1]))) { + if (contains(m_calltipParametersStart, strLine[current - 1])) + braces--; + else if (contains(m_calltipParametersEnd, strLine[current - 1])) + braces++; + current--; + pos--; + } + if (current > 0) { + current--; + pos--; + } else + break; + while (current > 0 && isspace(strLine[current - 1])) { + current--; + pos--; + } + } while (current > 0 && !contains(m_calltipWordCharacters, strLine[current - 1])); + if (current <= 0) + return true; + + m_nStartCalltipWord = current - 1; + while (m_nStartCalltipWord > 0 && + contains(m_calltipWordCharacters, strLine[m_nStartCalltipWord - 1])) { + m_nStartCalltipWord--; + } + + strLine.SetAt(current, '\0'); + m_currentCallTipWord = strLine.Mid(m_nStartCalltipWord); + m_functionDefinition.Empty(); + //Platform::DebugPrintf("word is [%s] %d %d %d\n", currentCallTipWord.c_str(), currentCallTipWord.length(), pos, pos - rootlen); + FillFunctionDefinition(pos); + return true; + } + + void CScintillaEx::ContinueCallTip() + { + CString strLine = GetLineText(); + int current = GetCaretInLine(); + const char* functionDefinition = m_functionDefinition; + + int braces = 0; + int commas = 0; + for (int i = m_nStartCalltipWord; i < current; i++) { + if (contains(m_calltipParametersStart, strLine[i])) + braces++; + else if (contains(m_calltipParametersEnd, strLine[i]) && braces > 0) + braces--; + else if (braces == 1 && contains(m_calltipParametersSeparators, strLine[i])) + commas++; + } + + int startHighlight = 0; + while (functionDefinition[startHighlight] && !contains(m_calltipParametersStart, m_functionDefinition[startHighlight])) + startHighlight++; + if (contains(m_calltipParametersStart, functionDefinition[startHighlight])) + startHighlight++; + while (functionDefinition[startHighlight] && commas > 0) { + if (contains(m_calltipParametersSeparators, functionDefinition[startHighlight])) + commas--; + // If it reached the end of the argument list it means that the user typed in more + // arguments than the ones listed in the calltip + if (contains(m_calltipParametersEnd, functionDefinition[startHighlight])) + commas = 0; + else + startHighlight++; + } + if (contains(m_calltipParametersSeparators, functionDefinition[startHighlight])) + startHighlight++; + int endHighlight = startHighlight; + while (functionDefinition[endHighlight] && !contains(m_calltipParametersSeparators, functionDefinition[endHighlight]) && !contains(m_calltipParametersEnd, functionDefinition[endHighlight])) + endHighlight++; + + // SendEditor(SCI_CALLTIPSETHLT, startHighlight, endHighlight); + CallTipSetHlt(startHighlight, endHighlight); + } + + /** + * Find the length of a 'word' which is actually an identifier in a string + * which looks like "identifier(..." or "identifier" and where + * there may be extra spaces after the identifier that should not be + * counted in the length. + */ + static unsigned int LengthWord(const char *word, char otherSeparator) { + // Find a '('. If that fails go to the end of the string. + const char *endWord = strchr(word, '('); + if (!endWord && otherSeparator) + endWord = strchr(word, otherSeparator); + if (!endWord) + endWord = word + strlen(word); + // Last case always succeeds so endWord != 0 + + // Drop any space characters. + if (endWord > word) { + endWord--; // Back from the '(', otherSeparator, or '\0' + // Move backwards over any spaces + // while ((endWord > word) && (IsASpace(*endWord))) { + while ((endWord > word) && (isspace(*endWord))) { + endWord--; + } + } + return endWord - word; + } + + /** + * Returns elements (first words of them) of the wordlist array which have + * the same beginning as the passed string. + * The length of the word to compare is passed too. + * Letter case can be ignored or preserved (default). + * If there are more words meeting the condition they are returned all of + * them in the ascending order separated with spaces. + */ + CString CScintillaEx::GetNearestWords( + CStringArray *arr, + const char *wordStart, + int searchLen, + bool ignoreCase /*= false*/, + char otherSeparator /*= '\0'*/, + bool exactLen /*=false*/) + { + unsigned int wordlen; // length of the word part (before the '(' brace) of the api array element + CString wordsNear; + int start = 0; // lower bound of the api array block to search + int end = arr->GetSize() - 1; // upper bound of the api array block to search + int pivot; // index of api array element just being compared + int cond; // comparison result (in the sense of strcmp() result) + + if (0 == arr->GetSize()) + return wordsNear; // is empty + if (ignoreCase) { + /* if (!sortedNoCase) { + sortedNoCase = true; + SortWordListNoCase(wordsNoCase, len); + } + */ + while (start <= end) { // Binary searching loop + pivot = (start + end) / 2; + cond = _strnicmp(wordStart, arr->GetAt(pivot), searchLen); + if (!cond) { + // Find first match + while ((pivot > start) && + (0 == _strnicmp(wordStart, arr->GetAt(pivot-1), searchLen))) { + --pivot; + } + // Grab each match + while ((pivot <= end) && + (0 == _strnicmp(wordStart, arr->GetAt(pivot), searchLen))) { + wordlen = LengthWord(arr->GetAt(pivot), otherSeparator) + 1; + ++pivot; + if (exactLen && wordlen != LengthWord(wordStart, otherSeparator) + 1) + continue; + if (!wordsNear.IsEmpty()) + wordsNear += ' '; + wordsNear += arr->GetAt(pivot-1).Left(wordlen); + } + return wordsNear; + } else if (cond < 0) { + end = pivot - 1; + } else if (cond > 0) { + start = pivot + 1; + } + } + } else { // Preserve the letter case + /* if (!sorted) { + sorted = true; + SortWordList(words, len); + } + */ + while (start <= end) { // Binary searching loop + pivot = (start + end) / 2; + cond = strncmp(wordStart, arr->GetAt(pivot), searchLen); + if (!cond) { + // Find first match + while ((pivot > start) && + (0 == strncmp(wordStart, + arr->GetAt(pivot-1), searchLen))) { + --pivot; + } + // Grab each match + while ((pivot <= end) && + (0 == strncmp(wordStart, arr->GetAt(pivot), searchLen))) { + wordlen = LengthWord(arr->GetAt(pivot), otherSeparator) + 1; + ++pivot; + if (exactLen && wordlen != LengthWord(wordStart, otherSeparator) + 1) + continue; + if (!wordsNear.IsEmpty()) + wordsNear += ' '; + wordsNear += arr->GetAt(pivot-1).Left(wordlen); + } + return wordsNear; + } else if (cond < 0) { + end = pivot - 1; + } else if (cond > 0) { + start = pivot + 1; + } + } + } + return wordsNear; // is empty + } + + void CScintillaEx::SetApi(CStringArray *api) + { + m_Api = api; + } + + /** + * Returns an element (complete) of the wordlist array which has + * the same beginning as the passed string. + * The length of the word to compare is passed too. + * Letter case can be ignored or preserved (default). + */ + const char *CScintillaEx::GetNearestWord(CStringArray *arr, const char *wordStart, int searchLen, bool ignoreCase /*= false*/, CString wordCharacters /*='/0' */, int wordIndex /*= -1 */) { + int start = 0; // lower bound of the api array block to search + int end = arr->GetSize() - 1; // upper bound of the api array block to search + int pivot; // index of api array element just being compared + int cond; // comparison result (in the sense of strcmp() result) + CString word; // api array element just being compared + + if (0 == arr->GetSize()) + return NULL; + if (ignoreCase) { + /* if (!sortedNoCase) { + sortedNoCase = true; + SortWordListNoCase(wordsNoCase, len); + } + */ + while (start <= end) { // binary searching loop + pivot = (start + end) >> 1; + word = arr->GetAt(pivot); + // cond = CompareNCaseInsensitive(wordStart, word, searchLen); + cond = _strnicmp(wordStart, word, searchLen); + if (!cond) { + // find first word + start = pivot; + while (start > 0 && !_strnicmp(wordStart, arr->GetAt(start-1), searchLen)) { + start--; + } + // find last word + end = pivot; + while (end < arr->GetSize() - 1 && !_strnicmp(wordStart, arr->GetAt(end+1), searchLen)) { + end++; + } + + // Finds first word in a series of equal words + for (pivot = start; pivot <= end; pivot++) { + word = arr->GetAt(pivot); + const char* w = word; + if (!contains(m_strWordCharacters, w[searchLen])) { + if (wordIndex <= 0) // Checks if a specific index was requested + return word; // result must not be freed with free() + wordIndex--; + } + } + return NULL; + } + else if (cond > 0) + start = pivot + 1; + else if (cond < 0) + end = pivot - 1; + } + } else { // preserve the letter case + /* if (!sorted) { + sorted = true; + SortWordList(words, len); + } + */ + while (start <= end) { // binary searching loop + pivot = (start + end) >> 1; + word = arr->GetAt(pivot); + cond = strncmp(wordStart, word, searchLen); + if (!cond) { + // find first word + start = pivot; + while (start > 0 && !strncmp(wordStart, arr->GetAt(start-1), searchLen)) { + start--; + } + // find last word + end = pivot; + while (end < arr->GetSize() - 1 && !strncmp(wordStart, arr->GetAt(end+1), searchLen)) { + end++; + } + + // Finds first word in a series of equal words + pivot = start; + while (pivot <= end) { + word = arr->GetAt(pivot); + const char* w = word; + if (!contains(m_strWordCharacters, w[searchLen])) { + if (wordIndex <= 0) // Checks if a specific index was requested + return word; // result must not be freed with free() + wordIndex--; + } + pivot++; + } + return NULL; + } + else if (cond > 0) + start = pivot + 1; + else if (cond < 0) + end = pivot - 1; + } + } + return NULL; + } + + /// Get line as string. + CString CScintillaEx::GetLineText(int nLine) + { + LPTSTR linebuf; + CString strLine; + + int nLen; + // Get needed buffer size + if (nLine < 0) + nLen = GetCurLine(0, 0); + else + nLen = GetLine(nLine, 0); + + // Allocate buffer + linebuf = strLine.GetBuffer(nLen + 1); + // And get the line + if (nLine < 0) + GetCurLine(nLen, linebuf); + else + GetLine(nLine, linebuf); + + linebuf[nLen] = '\0'; + strLine.ReleaseBuffer(); + + return strLine; + } + + void CScintillaEx::SetCalltipIgnoreCase(bool bIgnoreCase) + { + m_bCallTipIgnoreCase = bIgnoreCase; + } + + void CScintillaEx::SetCalltipWordCharacters(CString szWordCharacters) + { + m_calltipWordCharacters = szWordCharacters; + } + + void CScintillaEx::SetCalltipParametersStart(CString szParametersStart) + { + m_calltipParametersStart = szParametersStart; + } + + void CScintillaEx::SetCalltipParametersEnd(CString szParametersEnd) + { + m_calltipParametersEnd = szParametersEnd; + } + + void CScintillaEx::SetCalltipParametersSeparator(CString szParametersSeparator) + { + m_calltipParametersSeparators = szParametersSeparator; + } + + void CScintillaEx::SetCalltipEndDefinition(CString szEndDefinition) + { + m_calltipEndDefinition = szEndDefinition; + } + + bool CScintillaEx::StartAutoComplete() + { + CString line = GetLineText(); + int current = GetCaretInLine(); + + int startword = current; + + while ((startword > 0) && + (contains(m_calltipWordCharacters, line[startword - 1]) || + contains(m_autoCompleteStartCharacters, line[startword - 1]))) { + startword--; + } + + CString root = line.Mid(startword, current - startword); + if (m_Api && m_Api->GetSize() > 0) + { + CString words = GetNearestWords(m_Api, root, strlen(root), + m_bAutoCompleteIgnoreCase, m_calltipParametersStart[0]); + if (!words.IsEmpty()) { + EliminateDuplicateWords(words); + AutoCShow(strlen(root), words); + } + } + return true; + } + + void CScintillaEx::SetAutocompIgnoreCase(bool bIgnoreCase) + { + m_bAutoCompleteIgnoreCase = bIgnoreCase; + } + + void CScintillaEx::SetAutocompStartCharacters(CString szStartCharacters) + { + m_autoCompleteStartCharacters = szStartCharacters; + } + + void CScintillaEx::EliminateDuplicateWords(const char *words) + { + char *firstWord = (char *) words; + char *firstSpace = strchr(firstWord, ' '); + char *secondWord; + char *secondSpace; + int firstLen, secondLen; + + while (firstSpace) { + firstLen = firstSpace - firstWord; + secondWord = firstWord + firstLen + 1; + secondSpace = strchr(secondWord, ' '); + + if (secondSpace) + secondLen = secondSpace - secondWord; + else + secondLen = strlen(secondWord); + + if (firstLen == secondLen && + !strncmp(firstWord, secondWord, firstLen)) { + strcpy(firstWord, secondWord); + firstSpace = strchr(firstWord, ' '); + } else { + firstWord = secondWord; + firstSpace = secondSpace; + } + } + } + + bool CScintillaEx::ExistsApi() + { + return (m_Api && m_Api->GetSize() > 0); + } + + void CScintillaEx::SetSmartInsert(bool bSmartInsert) + { + m_bSmartInsert = bSmartInsert; + } + + void CScintillaEx::HighlightQuotation(long nPos) + { + long match = QuotationMatch(nPos); + if (match == INVALID_POSITION) + { + BraceHighlight(INVALID_POSITION, INVALID_POSITION); + BraceBadLight(nPos); + } + else + BraceHighlight(nPos, match); + } + + bool CScintillaEx::GetAutocompIgnoreCase() + { + return m_bAutoCompleteIgnoreCase; + } + + long CScintillaEx::QuotationMatch(long pos) + { + int ch = GetCharAt(pos); + int nOpposite = INVALID_POSITION; + int nStyle = GetStyleAt(pos); + int nLine = LineFromPosition(pos); + + // at first try to find quotation mark in same line + + // search forward to end of line + if (GetStyleAt(pos + 1) == nStyle) + { + for (int i = pos + 1; i < GetLineEndPosition(nLine); i++) + { + if (isspace(GetCharAt(i))) + continue; + if (GetStyleAt(i) != nStyle) + { + nOpposite = INVALID_POSITION; + break; + } + if (GetCharAt(i) == ch) + { + nOpposite = i; + break; + } + } + } + // search backward to begin of line if not found + if (nOpposite == INVALID_POSITION && GetStyleAt(pos - 1) == nStyle) + { + for (int i = pos - 1; i >= PositionFromLine(nLine); i--) + { + if (isspace(GetCharAt(i))) + continue; + if (GetStyleAt(i) != nStyle) + { + nOpposite = INVALID_POSITION; + break; + } + if (GetCharAt(i) == ch) + { + nOpposite = i; + break; + } + } + } + // search forward to end of file if not found + if (nOpposite == INVALID_POSITION && GetStyleAt(pos + 1) == nStyle) + { + for (int i = pos + 1; i < GetLength(); i++) + { + if (isspace(GetCharAt(i))) + continue; + if (GetStyleAt(i) != nStyle) + { + nOpposite = INVALID_POSITION; + break; + } + if (GetCharAt(i) == ch) + { + nOpposite = i; + break; + } + } + } + // search backward to begin of file if not found + if (nOpposite == INVALID_POSITION && GetStyleAt(pos - 1) == nStyle) + { + for (int i = pos - 1; i >= 0; i--) + { + if (isspace(GetCharAt(i))) + continue; + if (GetStyleAt(i) != nStyle) + { + nOpposite = INVALID_POSITION; + break; + } + if (GetCharAt(i) == ch) + { + nOpposite = i; + break; + } + } + } + return nOpposite; + } + + void CScintillaEx::SetSmartTab(bool bSmartTab) + { + m_bSmartTab = bSmartTab; + } + + /** Jump to next non white space position like in previous lines. + * If smart tab is available then tab gets current column and tries + * to find next non white space position like in previous lines. + * If previous line is too short then the next previous line is checked. + * EOLs are jump positions too. If new line is longer than all lines before + * tab inserts normal tabs. + */ + void CScintillaEx::TabExtended() + { + const int nMaxPreviousLines = 100; + + if (IsSelection() || !GetSmartTab()) + Tab(); + else + { + long nCurrentPos = GetCurrentPos(); + long nCurrentCol = GetColumn(nCurrentPos); + long nCurrentLine = GetCurLineNumber(); + long nNewCol = INVALID_POSITION; + long nFirstLine = nCurrentLine - nMaxPreviousLines; + if (nFirstLine < 0) + nFirstLine = 0; + for (int i = nCurrentLine - 1; i >= nFirstLine; i--) + { + if (GetColumn(GetLineEndPosition(i)) <= nCurrentCol) + continue; + long nPos = FindColumn(i, nCurrentCol); + // Find next white space + while (GetCharAt(nPos) != _T(' ') && GetCharAt(nPos) && _T('\t')) + { + if (GetCharAt(nPos) == _T('\r') || GetCharAt(nPos) == _T('\n')) + break; + nPos++; + } + // Find next non white space + while (GetCharAt(nPos) == _T(' ') || GetCharAt(nPos) == _T('\t')) + nPos++; + long nDiff = GetColumn(nPos) - nCurrentCol; + CString strIndent(' ', nDiff); + InsertText(-1, strIndent); + GotoPos(nCurrentPos + nDiff); + nNewCol = nCurrentCol + nDiff; + break; + } + if (nNewCol == INVALID_POSITION) + Tab(); + } + } + + bool CScintillaEx::GetSmartTab() + { + return m_bSmartTab; + } + + static bool isURLforsel(char ch) { + return !strchr("\t\n\r \"", ch); + } + + /// Select URL at current position + CString CScintillaEx::SelectionURL(int pos) + { + char selection[1000]; + int nStart = pos; + int nEnd = pos; + RangeExtendAndGrab(selection, 1000, nStart, nEnd, GetLength(), isURLforsel); + return CString(selection); + } + Index: ScintillaEx.h =================================================================== RCS file: /cvsroot/anyedit/AnyEditv2/ScintillaEx.h,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** ScintillaEx.h 12 Oct 2005 18:55:57 -0000 1.18 --- ScintillaEx.h 16 Oct 2005 12:23:23 -0000 1.19 *************** *** 94,97 **** --- 94,99 ---- { public: + bool StartCallTip(void); + CString GetLineText(int nLine = -1); void NumMinus(); void NumPlus(); *************** *** 156,159 **** --- 158,185 ---- protected: + bool m_bSmartTab; + bool m_bSmartInsert; + void EliminateDuplicateWords(const char *words); + bool m_bAutoCompleteIgnoreCase; + bool StartAutoComplete(void); + CString m_autoCompleteStartCharacters; + int m_nBraceCount; + int m_nStartCalltipWord; + CString m_calltipWordCharacters; + CString m_calltipParametersStart; + CString m_calltipParametersEnd; + CString m_calltipParametersSeparators; + CString m_calltipEndDefinition; + CString m_functionDefinition; + int m_nCurrentCallTip; + int m_nMaxCallTips; + bool m_bCallTipIgnoreCase; + CStringArray* m_Api; + const char *GetNearestWord(CStringArray *arr, const char *wordStart, int searchLen, bool ignoreCase = false, CString wordCharacters = "/0", int wordIndex = -1); + CString GetNearestWords(CStringArray *arr, const char *wordStart, int searchLen, bool ignoreCase = false, char otherSeparator = '\0', bool exactLen = false); + CString m_currentCallTipWord; + int m_lastPosCallTip; + void ContinueCallTip(void); + void FillFunctionDefinition(int pos = -1); bool m_bSaveConvertTabToSpaces; bool m_bSaveTrimTrailingSpaces; *************** *** 178,181 **** --- 204,228 ---- std::deque<int> dqBookmarks; public: + CString SelectionURL(int pos); + bool GetSmartTab(void); + void TabExtended(void); + void SetSmartTab(bool bSmartTab); + /** + * Find the position of a matching quotation or INVALID_POSITION if no match. + */ + long QuotationMatch(long pos); + bool GetAutocompIgnoreCase(void); + void HighlightQuotation(long nPos); + void SetSmartInsert(bool bSmartInsert); + bool ExistsApi(void); + void SetAutocompStartCharacters(CString szStartCharacters); + void SetAutocompIgnoreCase(bool bIgnoreCase); + void SetCalltipEndDefinition(CString szEndDefinition); + void SetCalltipParametersSeparator(CString szParametersSeparator); + void SetCalltipParametersEnd(CString szParametersEnd); + void SetCalltipParametersStart(CString szParametersStart); + void SetCalltipWordCharacters(CString szWordCharacters); + void SetCalltipIgnoreCase(bool bIgnoreCase); + void SetApi(CStringArray *api); CString GetEOLString(int nEOLMode = NULL); int GetSelectionEndLine(void); |