使用Godot 4过程中,有一点比较吸引我:代码自动补全
用RAD开发时,代码自动补全功能一直被吐槽,主要是速度慢
但我看Godot 4中的Script编写过程中,代码补全很快,这个可以研究一下。
研究代码可找到,代码补全触发过程
1) CodeTextEditor中创建时钟code_complete_timer,其timeout超时信号绑定_code_complete_timer_timeout函数。超时量缺省值为0.3,单位应该是秒。
code_complete_timer = memnew(Timer);
add_child(code_complete_timer);
code_complete_timer->set_one_shot(true);
code_complete_timer->set_wait_time(EDITOR_GET("text_editor/completion/code_complete_delay"));
...
code_complete_timer->connect("timeout", callable_mp(this, &CodeTextEditor::_code_complete_timer_timeout));
2) 编辑器中文本变化时,触发CodeTextEditor::_text_changed,时钟code_complete_timer开始计时。
void CodeTextEditor::_text_changed() {
if (text_editor->is_insert_text_operation()) {
code_complete_timer_line = text_editor->get_caret_line();
code_complete_timer->start();
}
idle->start();
if (find_replace_bar) {
find_replace_bar->needs_to_count_results = true;
}
}
而_line_col_changed函数(绑定caret_changed事件)会停止时钟。
void CodeTextEditor::_line_col_changed() {
if (!code_complete_timer->is_stopped() && code_complete_timer_line != text_editor->get_caret_line()) {
code_complete_timer->stop();
}
String line = text_editor->get_line(text_editor->get_caret_line());
int positional_column = 0;
for (int i = 0; i < text_editor->get_caret_column(); i++) {
if (line[i] == '\t') {
positional_column += text_editor->get_indent_size(); //tab size
} else {
positional_column += 1;
}
}
StringBuilder sb;
sb.append(itos(text_editor->get_caret_line() + 1).lpad(4));
sb.append(" : ");
sb.append(itos(positional_column + 1).lpad(3));
line_and_col_txt->set_text(sb.as_string());
if (find_replace_bar) {
if (!find_replace_bar->line_col_changed_for_result) {
find_replace_bar->needs_to_count_results = true;
}
find_replace_bar->line_col_changed_for_result = false;
}
}
3)时钟启动后在超时期内未被中止,则会触发timeout信号,调用_code_complete_timer_timeout
void CodeTextEditor::_code_complete_timer_timeout() {
if (!is_visible_in_tree()) {
return;
}
text_editor->request_code_completion();
}
在CodeEdit::request_code_completion函数中发出信号code_completion_requested
void CodeEdit::request_code_completion(bool p_force) {
if (GDVIRTUAL_CALL(_request_code_completion, p_force)) {
return;
}
/* Don't re-query if all existing options are quoted types, eg path, signal. */
bool ignored = code_completion_active && !code_completion_options.is_empty();
if (ignored) {
ScriptLanguage::CodeCompletionKind kind = ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT;
const ScriptLanguage::CodeCompletionOption *previous_option = nullptr;
for (int i = 0; i < code_completion_options.size(); i++) {
const ScriptLanguage::CodeCompletionOption ¤t_option = code_completion_options[i];
if (!previous_option) {
previous_option = ¤t_option;
kind = current_option.kind;
}
if (previous_option->kind != current_option.kind) {
ignored = false;
break;
}
}
ignored = ignored && (kind == ScriptLanguage::CODE_COMPLETION_KIND_FILE_PATH || kind == ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH || kind == ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL);
}
if (ignored) {
return;
}
if (p_force) {
emit_signal(SNAME("code_completion_requested"));
return;
}
String line = get_line(get_caret_line());
int ofs = CLAMP(get_caret_column(), 0, line.length());
if (ofs > 0 && (is_in_string(get_caret_line(), ofs) != -1 || !is_symbol(line[ofs - 1]) || code_completion_prefixes.has(line[ofs - 1]))) {
emit_signal(SNAME("code_completion_requested"));
} else if (ofs > 1 && line[ofs - 1] == ' ' && code_com

Godot4中的代码自动补全功能通过CodeTextEditor组件实现,利用时钟定时器_code_complete_timer触发。当文本改变时,开始计时,若在设定时间内无中断,则调用_code_complete_timer_timeout请求代码补全。在GDScript中,完成代码补全涉及语法解析、语义分析和候选选项处理。该机制提升了开发效率。
最低0.47元/天 解锁文章

3368

被折叠的 条评论
为什么被折叠?



