2019-06-14 22:38:54 +08:00
/**************************************************************************/
/* gdscript_language_server.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
# include "gdscript_language_server.h"
2020-06-08 11:00:07 +02:00
2026-03-12 21:17:06 +01:00
# include "gdscript_language_protocol.h"
2019-06-14 22:38:54 +08:00
# include "core/os/os.h"
2019-12-24 15:17:23 +08:00
# include "editor/editor_log.h"
2019-06-14 22:38:54 +08:00
# include "editor/editor_node.h"
2025-06-10 16:47:26 +02:00
# include "editor/settings/editor_settings.h"
2019-06-14 22:38:54 +08:00
2023-09-17 22:09:18 -05:00
int GDScriptLanguageServer : : port_override = - 1 ;
2019-06-14 22:38:54 +08:00
GDScriptLanguageServer : : GDScriptLanguageServer ( ) {
2025-06-30 13:53:07 +02:00
set_process_internal ( true ) ;
2019-06-14 22:38:54 +08:00
}
void GDScriptLanguageServer : : _notification ( int p_what ) {
switch ( p_what ) {
2022-02-16 09:17:55 -05:00
case NOTIFICATION_EXIT_TREE : {
2019-06-14 22:38:54 +08:00
stop ( ) ;
2022-02-16 09:17:55 -05:00
} break ;
2020-01-11 23:50:32 +08:00
case NOTIFICATION_INTERNAL_PROCESS : {
2025-10-05 16:09:21 +02:00
if ( ! start_attempted & & EditorNode : : get_singleton ( ) - > is_editor_ready ( ) ) {
start_attempted = true ;
2025-06-30 13:53:07 +02:00
start ( ) ;
}
2020-01-11 23:50:32 +08:00
if ( started & & ! use_thread ) {
2025-06-08 16:12:33 +02:00
GDScriptLanguageProtocol : : get_singleton ( ) - > poll ( poll_limit_usec ) ;
2020-01-11 23:50:32 +08:00
}
} break ;
2022-02-16 09:17:55 -05:00
2020-01-11 23:50:32 +08:00
case EditorSettings : : NOTIFICATION_EDITOR_SETTINGS_CHANGED : {
2022-11-23 00:14:08 +01:00
if ( ! EditorSettings : : get_singleton ( ) - > check_changed_settings_in_group ( " network/language_server " ) ) {
break ;
}
2022-09-29 12:53:28 +03:00
String remote_host = String ( _EDITOR_GET ( " network/language_server/remote_host " ) ) ;
2023-09-17 22:09:18 -05:00
int remote_port = ( GDScriptLanguageServer : : port_override > - 1 ) ? GDScriptLanguageServer : : port_override : ( int ) _EDITOR_GET ( " network/language_server/remote_port " ) ;
2022-09-29 12:53:28 +03:00
bool remote_use_thread = ( bool ) _EDITOR_GET ( " network/language_server/use_thread " ) ;
2024-03-08 15:24:51 +01:00
int remote_poll_limit = ( int ) _EDITOR_GET ( " network/language_server/poll_limit_usec " ) ;
if ( remote_host ! = host | | remote_port ! = port | | remote_use_thread ! = use_thread | | remote_poll_limit ! = poll_limit_usec ) {
2022-09-29 12:53:28 +03:00
stop ( ) ;
start ( ) ;
2020-01-11 23:50:32 +08:00
}
} break ;
2019-06-14 22:38:54 +08:00
}
}
void GDScriptLanguageServer : : thread_main ( void * p_userdata ) {
2023-08-16 16:29:28 +03:00
set_current_thread_safe_for_nodes ( true ) ;
2019-06-14 22:38:54 +08:00
GDScriptLanguageServer * self = static_cast < GDScriptLanguageServer * > ( p_userdata ) ;
2020-01-11 23:50:32 +08:00
while ( self - > thread_running ) {
2019-10-10 16:41:36 +02:00
// Poll 20 times per second
2025-06-08 16:12:33 +02:00
GDScriptLanguageProtocol : : get_singleton ( ) - > poll ( self - > poll_limit_usec ) ;
2019-10-10 16:41:36 +02:00
OS : : get_singleton ( ) - > delay_usec ( 50000 ) ;
2019-06-14 22:38:54 +08:00
}
}
void GDScriptLanguageServer : : start ( ) {
2021-09-01 18:56:19 -04:00
host = String ( _EDITOR_GET ( " network/language_server/remote_host " ) ) ;
2023-09-17 22:09:18 -05:00
port = ( GDScriptLanguageServer : : port_override > - 1 ) ? GDScriptLanguageServer : : port_override : ( int ) _EDITOR_GET ( " network/language_server/remote_port " ) ;
2020-01-11 23:50:32 +08:00
use_thread = ( bool ) _EDITOR_GET ( " network/language_server/use_thread " ) ;
2024-03-08 15:24:51 +01:00
poll_limit_usec = ( int ) _EDITOR_GET ( " network/language_server/poll_limit_usec " ) ;
2026-02-03 21:33:52 +01:00
const Error status = GDScriptLanguageProtocol : : get_singleton ( ) - > start ( port , IPAddress ( host ) ) ;
if ( status ! = OK ) {
EditorNode : : get_log ( ) - > add_message ( " --- Failed to start GDScript language server on port " + itos ( port ) + " : " + error_names [ status ] + " --- " , EditorLog : : MSG_TYPE_EDITOR ) ;
return ;
2019-06-14 22:38:54 +08:00
}
2026-02-03 21:33:52 +01:00
EditorNode : : get_log ( ) - > add_message ( " --- GDScript language server started on port " + itos ( port ) + " --- " , EditorLog : : MSG_TYPE_EDITOR ) ;
if ( use_thread ) {
thread_running = true ;
thread . start ( GDScriptLanguageServer : : thread_main , this ) ;
}
set_process_internal ( ! use_thread ) ;
started = true ;
2019-06-14 22:38:54 +08:00
}
void GDScriptLanguageServer : : stop ( ) {
2020-01-11 23:50:32 +08:00
if ( use_thread ) {
2021-01-19 13:29:41 +01:00
ERR_FAIL_COND ( ! thread . is_started ( ) ) ;
2020-01-11 23:50:32 +08:00
thread_running = false ;
2021-01-19 13:29:41 +01:00
thread . wait_to_finish ( ) ;
2020-01-11 23:50:32 +08:00
}
2025-06-08 16:12:33 +02:00
GDScriptLanguageProtocol : : get_singleton ( ) - > stop ( ) ;
2020-01-11 23:50:32 +08:00
started = false ;
2019-09-20 01:56:09 +02:00
EditorNode : : get_log ( ) - > add_message ( " --- GDScript language server stopped --- " , EditorLog : : MSG_TYPE_EDITOR ) ;
2019-06-14 22:38:54 +08:00
}
void register_lsp_types ( ) {
2021-07-11 19:30:33 -03:00
GDREGISTER_CLASS ( GDScriptLanguageProtocol ) ;
GDREGISTER_CLASS ( GDScriptTextDocument ) ;
GDREGISTER_CLASS ( GDScriptWorkspace ) ;
2019-06-14 22:38:54 +08:00
}