summaryrefslogtreecommitdiff
path: root/third_party
diff options
context:
space:
mode:
Diffstat (limited to 'third_party')
-rw-r--r--third_party/linenoise/linenoise.cpp201
1 files changed, 98 insertions, 103 deletions
diff --git a/third_party/linenoise/linenoise.cpp b/third_party/linenoise/linenoise.cpp
index 52faa72d98c..e11f77cfd7e 100644
--- a/third_party/linenoise/linenoise.cpp
+++ b/third_party/linenoise/linenoise.cpp
@@ -223,7 +223,6 @@ static string previousSearchText;
// changing prompt for "(reverse-i-search)`text':" etc.
//
struct DynamicPrompt : public PromptBase {
- PromptInfo& realPrompt; // the prompt we are drawing over
char* searchText; // text we are searching for
int searchTextLen; // chars in searchText
int direction; // current search direction, 1=forward, -1=reverse
@@ -231,7 +230,7 @@ struct DynamicPrompt : public PromptBase {
int reverseSearchBasePromptLen;
int endSearchBasePromptLen;
- DynamicPrompt( PromptInfo& pi, int initialDirection ) : realPrompt( pi ), direction( initialDirection ) {
+ DynamicPrompt( PromptInfo& pi, int initialDirection ) : direction( initialDirection ) {
forwardSearchBasePromptLen = strlen( forwardSearchBasePrompt ); // store constant text lengths
reverseSearchBasePromptLen = strlen( reverseSearchBasePrompt );
endSearchBasePromptLen = strlen( endSearchBasePrompt );
@@ -342,6 +341,24 @@ public:
};
+struct InputBuffer {
+ char* buf;
+ int buflen;
+ int len;
+ int pos;
+
+ InputBuffer( char* buffer, int bufferLen ) : buf( buffer ), buflen( bufferLen - 1 ), len( 0 ), pos( 0 ) {
+ buf[0] = 0;
+ }
+
+ int getInputLine( PromptInfo& pi );
+ void refreshLine( PromptBase& pi );
+ int completeLine( PromptInfo& pi );
+ void clearScreen( PromptInfo& pi );
+ int incrementalHistorySearch( PromptInfo& pi, int startChar );
+
+};
+
// Special codes for keyboard input:
//
// Between Windows and the various Linux "terminal" programs, there is some
@@ -393,7 +410,6 @@ static int historyMaxLen = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
static int historyLen = 0;
static int historyIndex = 0;
static char** history = NULL;
-static const char* emptyString = "";
static void linenoiseAtExit( void );
@@ -610,11 +626,8 @@ static void dynamicRefresh( PromptBase& pi, char *buf, int len, int pos ) {
/**
* Refresh the user's input line: the prompt is already onscreen and is not redrawn here
* @param pi PromptInfo struct holding information about the prompt and our screen position
- * @param buf input buffer to be displayed
- * @param len count of characters in the buffer
- * @param pos current cursor position within the buffer (0 <= pos <= len)
*/
-static void refreshLine( PromptBase& pi, const char *buf, int len, int pos ) {
+void InputBuffer::refreshLine( PromptBase& pi ) {
// check for a matching brace/bracket/paren, remember its position if found
int highlight = -1;
@@ -1104,25 +1117,21 @@ static const char breakChars[] = " =+-/\\*?\"'`&<>;|@{([])}";
* This routine handles the mechanics of updating the user's input buffer with possible replacement of
* text as the user selects a proposed completion string, or cancels the completion attempt.
* @param pi PromptInfo struct holding information about the prompt and our screen position
- * @param buf input buffer to be displayed
- * @param buflen size of input buffer in bytes
- * @param len ptr to count of characters in the buffer (updated)
- * @param pos ptr to current cursor position within the buffer (0 <= pos <= len) (updated)
*/
-static int completeLine( PromptInfo& pi, char *buf, int buflen, int *len, int *pos ) {
+int InputBuffer::completeLine( PromptInfo& pi ) {
linenoiseCompletions lc = { 0, NULL };
char c = 0;
// completionCallback() expects a parsable entity, so find the previous break character and extract
// a copy to parse. we also handle the case where tab is hit while not at end-of-line.
- int startIndex = *pos;
+ int startIndex = pos;
while ( --startIndex >= 0 ) {
if ( strchr( breakChars, buf[startIndex] ) ) {
break;
}
}
++startIndex;
- int itemLength = *pos - startIndex;
+ int itemLength = pos - startIndex;
char* parseItem = reinterpret_cast<char *>( malloc( itemLength + 1 ) );
int i = 0;
for ( ; i < itemLength; ++i ) {
@@ -1147,19 +1156,22 @@ static int completeLine( PromptInfo& pi, char *buf, int buflen, int *len, int *p
/* Show completion or original buffer */
if ( i < lc.len ) {
clen = strlen( lc.cvec[i] );
- displayLength = *len + clen - itemLength;
+ displayLength = len + clen - itemLength;
displayText = reinterpret_cast<char *>( malloc( displayLength + 1 ) );
+ InputBuffer temp( displayText, displayLength + 1 );
+ temp.len = displayLength;
+ temp.pos = startIndex + clen;
int j = 0;
for ( ; j < startIndex; ++j )
displayText[j] = buf[j];
strcpy( &displayText[j], lc.cvec[i] );
- strcpy( &displayText[j+clen], &buf[*pos] );
+ strcpy( &displayText[j+clen], &buf[pos] );
displayText[displayLength] = 0;
- refreshLine( pi, displayText, displayLength, startIndex + clen );
+ temp.refreshLine( pi );
free( displayText );
}
else {
- refreshLine( pi, buf, *len, *pos );
+ refreshLine( pi );
}
do {
@@ -1192,18 +1204,18 @@ static int completeLine( PromptInfo& pi, char *buf, int buflen, int *len, int *p
/* Update buffer and return */
if ( i < lc.len ) {
clen = strlen( lc.cvec[i] );
- displayLength = *len + clen - itemLength;
+ displayLength = len + clen - itemLength;
displayText = (char *)malloc( displayLength + 1 );
int j = 0;
for ( ; j < startIndex; ++j )
displayText[j] = buf[j];
strcpy( &displayText[j], lc.cvec[i] );
- strcpy( &displayText[j+clen], &buf[*pos] );
+ strcpy( &displayText[j+clen], &buf[pos] );
displayText[displayLength] = 0;
strcpy( buf, displayText );
free( displayText );
- *pos = startIndex + clen;
- *len = displayLength;
+ pos = startIndex + clen;
+ len = displayLength;
}
stop = true;
break;
@@ -1215,7 +1227,7 @@ static int completeLine( PromptInfo& pi, char *buf, int buflen, int *len, int *p
return c; /* Return last read character */
}
-static void linenoiseClearScreen( PromptInfo& pi, char *buf, int len, int pos ) {
+void InputBuffer::clearScreen( PromptInfo& pi ) {
#ifdef _WIN32
COORD coord = {0, 0};
@@ -1234,7 +1246,7 @@ static void linenoiseClearScreen( PromptInfo& pi, char *buf, int len, int pos )
if ( write( 1, "\n", 1 ) == -1 ) return;
#endif
pi.promptCursorRowOffset = pi.promptExtraLines;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
// convert {CTRL + 'A'}, {CTRL + 'a'} and {CTRL + ctrlChar( 'A' )} into ctrlChar( 'A' )
@@ -1261,20 +1273,18 @@ static int cleanupCtrl( int c ) {
* deletes characters from it, changes direction, and either accepts the found line (for execution or
* editing) or cancels.
* @param pi PromptInfo struct holding information about the (old, static) prompt and our screen position
- * @param buf input buffer to be displayed
- * @param buflen size of input buffer in bytes
- * @param len ptr to count of characters in the buffer (updated)
- * @param pos ptr to current cursor position within the buffer (0 <= pos <= len) (updated)
* @param startChar the character that began the search, used to set the initial direction
*/
-int incrementalHistorySearch( PromptInfo& pi, char *buf, int buflen, int *len, int *pos, int startChar ) {
+int InputBuffer::incrementalHistorySearch( PromptInfo& pi, int startChar ) {
// add the current line to the history list so we don't have to special case it
- history[historyLen - 1] = reinterpret_cast<char *>( realloc( history[historyLen - 1], *len + 1 ) );
+ history[historyLen - 1] = reinterpret_cast<char *>( realloc( history[historyLen - 1], len + 1 ) );
strcpy( history[historyLen - 1], buf );
- int historyLineLength = *len;
- int historyLinePosition = *pos;
- refreshLine( pi, emptyString, 0, 0 ); // erase the old input first
+ int historyLineLength = len;
+ int historyLinePosition = pos;
+ char emptyBuffer[1];
+ InputBuffer empty( emptyBuffer, 1 );
+ empty.refreshLine( pi ); // erase the old input first
DynamicPrompt dp( pi, ( startChar == ctrlChar( 'R' ) ) ? -1 : 1 );
dp.previousPromptLen = pi.previousPromptLen;
@@ -1454,26 +1464,19 @@ int incrementalHistorySearch( PromptInfo& pi, char *buf, int buflen, int *len, i
pb.previousPromptLen = dp.promptChars;
if ( useSearchedLine ) {
strcpy( buf, history[historyIndex] );
- *len = historyLineLength;
- *pos = historyLinePosition;
+ len = historyLineLength;
+ pos = historyLinePosition;
}
- dynamicRefresh( pb, buf, *len, *pos ); // redraw the original prompt with current input
- pi.promptPreviousInputLen = *len;
+ dynamicRefresh( pb, buf, len, pos ); // redraw the original prompt with current input
+ pi.promptPreviousInputLen = len;
pi.promptCursorRowOffset = pi.promptExtraLines + pb.promptCursorRowOffset;
previousSearchText = dp.searchText; // save search text for possible reuse on ctrl-R ctrl-R
return c; // pass a character or -1 back to main loop
}
-static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
- int pos = 0;
- int len = 0;
-
- buf[0] = '\0';
- buflen--; /* Make sure there is always space for the nulterm */
-
- /* The latest history entry is always our current buffer, that
- * initially is just an empty string. */
+int InputBuffer::getInputLine( PromptInfo& pi ) {
+ // The latest history entry is always our current buffer
linenoiseHistoryAdd( "" );
historyIndex = historyLen - 1;
@@ -1511,7 +1514,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
return len;
if ( c == -1 ) {
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
continue;
}
@@ -1520,7 +1523,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
killRing.lastAction = KillRing::actionOther;
// completeLine does the actual completion and replacement
- c = completeLine( pi, buf, buflen, &len, &pos );
+ c = completeLine( pi );
if ( c < 0 ) // return on error
return len;
@@ -1537,7 +1540,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
case HOME_KEY:
killRing.lastAction = KillRing::actionOther;
pos = 0;
- refreshLine( pi ,buf, len, pos );
+ refreshLine( pi );
break;
case ctrlChar( 'B' ): // ctrl-B, move cursor left by one character
@@ -1545,7 +1548,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
killRing.lastAction = KillRing::actionOther;
if ( pos > 0 ) {
--pos;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
break;
@@ -1561,7 +1564,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
while ( pos > 0 && isalnum( buf[pos - 1] ) ) {
--pos;
}
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
break;
@@ -1572,7 +1575,8 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
free( history[historyLen] );
// we need one last refresh with the cursor at the end of the line
// so we don't display the next prompt over the previous input line
- refreshLine( pi, buf, len, len ); // pass len as pos for EOL
+ pos = len; // pass len as pos for EOL
+ refreshLine( pi );
if ( write( 1, "^C", 2 ) == -1 ) return -1; // Display the ^C we got
return -1;
@@ -1583,7 +1587,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
if ( len > 0 && pos < len ) {
memmove( buf + pos, buf + pos + 1, len - pos );
--len;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
else if ( len == 0 ) {
--historyLen;
@@ -1605,7 +1609,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
killRing.kill( &buf[pos], endingPos - pos, true );
memmove( buf + pos, buf + endingPos, len - endingPos + 1 );
len -= endingPos - pos;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
killRing.lastAction = KillRing::actionKill;
break;
@@ -1614,7 +1618,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
case END_KEY:
killRing.lastAction = KillRing::actionOther;
pos = len;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
break;
case ctrlChar( 'F' ): // ctrl-F, move cursor right by one character
@@ -1622,7 +1626,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
killRing.lastAction = KillRing::actionOther;
if ( pos < len ) {
++pos;
- refreshLine( pi ,buf, len, pos );
+ refreshLine( pi );
}
break;
@@ -1638,7 +1642,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
while ( pos < len && isalnum( buf[pos] ) ) {
++pos;
}
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
break;
@@ -1648,7 +1652,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
memmove( buf + pos - 1, buf + pos, 1 + len - pos );
--pos;
--len;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
break;
@@ -1665,7 +1669,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
killRing.kill( &buf[pos], startingPos - pos, false );
memmove( buf + pos, buf + startingPos, len - startingPos + 1 );
len -= startingPos - pos;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
killRing.lastAction = KillRing::actionKill;
break;
@@ -1675,7 +1679,8 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
killRing.lastAction = KillRing::actionOther;
// we need one last refresh with the cursor at the end of the line
// so we don't display the next prompt over the previous input line
- refreshLine( pi, buf, len, len ); // pass len as pos for EOL
+ pos = len; // pass len as pos for EOL
+ refreshLine( pi );
--historyLen;
free( history[historyLen] );
return len;
@@ -1684,12 +1689,12 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
killRing.kill( &buf[pos], len - pos, true );
buf[pos] = '\0';
len = pos;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
killRing.lastAction = KillRing::actionKill;
break;
case ctrlChar( 'L' ): // ctrl-L, clear screen and redisplay line
- linenoiseClearScreen( pi, buf, len, pos );
+ clearScreen( pi );
break;
case ctrlChar( 'N' ): // ctrl-N, recall next line in history
@@ -1718,13 +1723,13 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
strncpy( buf, history[historyIndex], buflen );
buf[buflen] = '\0';
len = pos = strlen( buf ); // place cursor at end of line
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
break;
case ctrlChar( 'R' ): // ctrl-R, reverse history search
case ctrlChar( 'S' ): // ctrl-S, forward history search
- terminatingKeystroke = incrementalHistorySearch( pi, buf, buflen, &len, &pos, c );
+ terminatingKeystroke = incrementalHistorySearch( pi, c );
break;
case ctrlChar( 'T' ): // ctrl-T, transpose characters
@@ -1736,7 +1741,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
buf[leftCharPos+1] = aux;
if ( pos != len )
++pos;
- refreshLine( pi ,buf, len, pos );
+ refreshLine( pi );
}
break;
@@ -1746,7 +1751,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
len -= pos;
memmove( buf, buf + pos, len + 1 );
pos = 0;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
killRing.lastAction = KillRing::actionKill;
break;
@@ -1764,7 +1769,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
killRing.kill( &buf[pos], startingPos - pos, false );
memmove( buf + pos, buf + startingPos, len - startingPos + 1 );
len -= startingPos - pos;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
killRing.lastAction = KillRing::actionKill;
break;
@@ -1778,7 +1783,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
memmove( buf + pos, restoredText->c_str(), restoredTextLen );
pos += restoredTextLen;
len += restoredTextLen;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
killRing.lastAction = KillRing::actionYank;
killRing.lastYankSize = restoredTextLen;
}
@@ -1805,7 +1810,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
pos += restoredTextLen - killRing.lastYankSize;
len += restoredTextLen - killRing.lastYankSize;
killRing.lastYankSize = restoredTextLen;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
break;
}
}
@@ -1818,7 +1823,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
raise( SIGSTOP ); // Break out in mid-line
enableRawMode(); // Back from Linux shell, re-enter raw mode
if ( write( 1, pi.promptText, pi.promptChars ) == -1 ) break; // Redraw prompt
- refreshLine( pi, buf, len, pos ); // Refresh the line
+ refreshLine( pi ); // Refresh the line
break;
#endif
@@ -1829,7 +1834,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
if ( len > 0 && pos < len ) {
memmove( buf + pos, buf + pos + 1, len - pos );
--len;
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
break;
@@ -1858,7 +1863,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
if ( write( 1, &c, 1) == -1 ) return -1;
}
else {
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
}
else { // not at end of buffer, have to move characters to our right
@@ -1867,7 +1872,7 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
++len;
++pos;
buf[len] = '\0';
- refreshLine( pi, buf, len, pos );
+ refreshLine( pi );
}
}
break;
@@ -1876,49 +1881,39 @@ static int linenoisePrompt( char *buf, int buflen, PromptInfo& pi ) {
return len;
}
-static int linenoiseRaw( char* buf, int buflen, PromptInfo& pi ) {
+/**
+ * linenoise is a readline replacement.
+ *
+ * call it with a prompt to display and it will return a line of input from the user
+ *
+ * @param prompt text of prompt to display to the user
+ * @return the returned string belongs to the caller on return and must be freed to prevent memory leaks
+ */
+char* linenoise( const char* prompt ) {
+ char buf[LINENOISE_MAX_LINE]; // buffer for user's input
int count;
-
- if ( buflen == 0 ) {
- errno = EINVAL;
- return -1;
- }
-
- if ( isatty( STDIN_FILENO ) ) { // input is from a terminal
+ if ( isatty( STDIN_FILENO ) ) { // input is from a terminal
if ( enableRawMode() == -1 )
- return -1;
- count = linenoisePrompt( buf, buflen, pi );
+ return NULL;
+ PromptInfo pi( prompt, getColumns() ); // struct to hold edited copy of prompt & misc prompt info
+ InputBuffer ib( buf, LINENOISE_MAX_LINE );
+ count = ib.getInputLine( pi );
disableRawMode();
printf( "\n" );
+ if ( count == -1 )
+ return NULL;
}
else { // input not from a terminal, we should work with piped input, i.e. redirected stdin
- if ( fgets( buf, buflen, stdin ) == NULL )
- return -1;
- count = strlen( buf );
+ if ( fgets( buf, sizeof buf, stdin ) == NULL )
+ return NULL;
// if fgets() gave us the newline, remove it
+ int count = strlen( buf );
if ( count && buf[count-1] == '\n' ) {
--count;
buf[count] = '\0';
}
}
- return count;
-}
-
-/**
- * linenoise is a readline replacement.
- *
- * call it with a prompt to display and it will return a line of input from the user
- *
- * @param prompt text of prompt to display to the user
- * @return the returned string belongs to the caller on return and must be freed to prevent memory leaks
- */
-char* linenoise( const char* prompt ) {
- char buf[LINENOISE_MAX_LINE]; // buffer for user's input
- PromptInfo pi( prompt, getColumns() ); // struct to hold edited copy of prompt & misc prompt info
- if ( linenoiseRaw( buf, LINENOISE_MAX_LINE, pi ) == -1 ) {
- return NULL;
- }
return strdup( buf ); // caller must free buffer
}