File indexing completed on 2024-05-19 04:55:50
0001 /** 0002 * \file readlinecompleter.cpp 0003 * Abstract base class for readline completer. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 22 Sep 2013 0008 * 0009 * Copyright (C) 2013-2024 Urs Fleisch 0010 * 0011 * This file is part of Kid3. 0012 * 0013 * Kid3 is free software; you can redistribute it and/or modify 0014 * it under the terms of the GNU General Public License as published by 0015 * the Free Software Foundation; either version 2 of the License, or 0016 * (at your option) any later version. 0017 * 0018 * Kid3 is distributed in the hope that it will be useful, 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0021 * GNU General Public License for more details. 0022 * 0023 * You should have received a copy of the GNU General Public License 0024 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0025 */ 0026 0027 #include "readlinecompleter.h" 0028 0029 #include <cstdio> 0030 #include <readline/readline.h> 0031 #include <cstdlib> 0032 0033 /** Installed readline completer. */ 0034 ReadlineCompleter* ReadlineCompleter::s_completer = nullptr; 0035 0036 /** 0037 * Destructor. 0038 */ 0039 ReadlineCompleter::~ReadlineCompleter() 0040 { 0041 } 0042 0043 /** 0044 * Install this completer to be used with readline. 0045 */ 0046 void ReadlineCompleter::install() 0047 { 0048 s_completer = this; 0049 ::rl_attempted_completion_function = completion; 0050 #if RL_READLINE_VERSION > 0x0402 0051 ::rl_completer_quote_characters = "\""; 0052 ::rl_filename_quote_characters = " '\"\\\t"; 0053 #else 0054 ::rl_completer_quote_characters = const_cast<char*>("\""); 0055 #endif 0056 } 0057 0058 /** 0059 * Readline completion function. 0060 * @param text contents to complete 0061 * @param start start index in rl_line_buffer of word to complete 0062 * @param end end index in rl_line_buffer of word to complete 0063 * @return array of matches or 0 if there aren't any. 0064 */ 0065 char** ReadlineCompleter::completion(const char* text, int start, int end) 0066 { 0067 Q_UNUSED(end) 0068 char** matches = nullptr; 0069 0070 if (start == 0) { 0071 matches = ::rl_completion_matches(text, commandGenerator); 0072 } else if (s_completer) { 0073 if (s_completer->updateParameterList(::rl_line_buffer)) { 0074 matches = ::rl_completion_matches(text, parameterGenerator); 0075 if (!matches) { 0076 ::rl_attempted_completion_over = 1; 0077 } 0078 } else { 0079 #if RL_READLINE_VERSION > 0x0402 0080 ::rl_filename_quoting_desired = 1; 0081 #endif 0082 } 0083 } 0084 0085 return matches; 0086 } 0087 0088 /** 0089 * Readline command generator. 0090 * @param text partial word to be completed 0091 * @param state 0 for first call, >0 for subsequent calls 0092 * @return next completion string, allocated with malloc(), 0 if there are 0093 * no more possibilities left. 0094 */ 0095 char* ReadlineCompleter::commandGenerator(const char* text, int state) 0096 { 0097 if (s_completer) { 0098 return completionGenerator(s_completer->getCommandList(), text, state); 0099 } 0100 return nullptr; 0101 } 0102 0103 /** 0104 * Readline parameter generator. 0105 * @param text partial word to be completed 0106 * @param state 0 for first call, >0 for subsequent calls 0107 * @return next completion string, allocated with malloc(), 0 if there are 0108 * no more possibilities left. 0109 */ 0110 char* ReadlineCompleter::parameterGenerator(const char* text, int state) 0111 { 0112 if (s_completer) { 0113 return completionGenerator(s_completer->getParameterList(), text, state); 0114 } 0115 return nullptr; 0116 } 0117 0118 /** 0119 * Readline completion generator. 0120 * @param completions list of completions 0121 * @param text partial word to be completed 0122 * @param state 0 for first call, >0 for subsequent calls 0123 * @return next completion string, allocated with malloc(), 0 if there are 0124 * no more possibilities left. 0125 */ 0126 char* ReadlineCompleter::completionGenerator( 0127 const QList<QByteArray>& completions, const char* text, int state) 0128 { 0129 static int listIndex, textLen; 0130 if (state == 0) { 0131 listIndex = 0; 0132 textLen = qstrlen(text); 0133 } 0134 0135 while (listIndex < completions.size()) { 0136 if (const QByteArray& name = completions.at(listIndex++); 0137 name.left(textLen) == text) { 0138 auto r = static_cast<char*>(::malloc(name.length() + 1)); 0139 qstrcpy(r, name.constData()); 0140 return r; 0141 } 0142 } 0143 0144 return nullptr; 0145 }