Allow dehardcoding documentation branch and URL in docs links

This makes it possible to change the branch of the documentation that
URLs are pointing to without having to modify all class reference
files.

In the XML class reference, the `$DOCS_URL` placeholder should be used,
and will be replaced automatically in the editor and when generating
the RST class reference.

The documentation branch string is set in `version.py`.

Co-authored-by: Hugo Locurcio <hugo.locurcio@hugo.pro>
This commit is contained in:
Rémi Verschelde 2021-11-15 10:39:00 +01:00
parent 9e1c190ce1
commit 5341e6010e
No known key found for this signature in database
GPG Key ID: C3336907360768E1
7 changed files with 46 additions and 34 deletions

View File

@ -38,6 +38,7 @@
#include "core/string/translation.h" #include "core/string/translation.h"
#include "core/string/ucaps.h" #include "core/string/ucaps.h"
#include "core/variant/variant.h" #include "core/variant/variant.h"
#include "core/version_generated.gen.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -4868,15 +4869,20 @@ String TTRN(const String &p_text, const String &p_text_plural, int p_n, const St
return p_text_plural; return p_text_plural;
} }
/* DTR and DTRN are used for the documentation, handling descriptions extracted
* from the XML.
* They also replace `$DOCS_URL` with the actual URL to the documentation's branch,
* to allow dehardcoding it in the XML and doing proper substitutions everywhere.
*/
String DTR(const String &p_text, const String &p_context) { String DTR(const String &p_text, const String &p_context) {
// Comes straight from the XML, so remove indentation and any trailing whitespace. // Comes straight from the XML, so remove indentation and any trailing whitespace.
const String text = p_text.dedent().strip_edges(); const String text = p_text.dedent().strip_edges();
if (TranslationServer::get_singleton()) { if (TranslationServer::get_singleton()) {
return TranslationServer::get_singleton()->doc_translate(text, p_context); return String(TranslationServer::get_singleton()->doc_translate(text, p_context)).replace("$DOCS_URL", VERSION_DOCS_URL);
} }
return text; return text.replace("$DOCS_URL", VERSION_DOCS_URL);
} }
String DTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) { String DTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) {
@ -4884,14 +4890,14 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St
const String text_plural = p_text_plural.dedent().strip_edges(); const String text_plural = p_text_plural.dedent().strip_edges();
if (TranslationServer::get_singleton()) { if (TranslationServer::get_singleton()) {
return TranslationServer::get_singleton()->doc_translate_plural(text, text_plural, p_n, p_context); return String(TranslationServer::get_singleton()->doc_translate_plural(text, text_plural, p_n, p_context)).replace("$DOCS_URL", VERSION_DOCS_URL);
} }
// Return message based on English plural rule if translation is not possible. // Return message based on English plural rule if translation is not possible.
if (p_n == 1) { if (p_n == 1) {
return text; return text.replace("$DOCS_URL", VERSION_DOCS_URL);
} }
return text_plural; return text_plural.replace("$DOCS_URL", VERSION_DOCS_URL);
} }
#endif #endif

View File

@ -11,10 +11,8 @@ from collections import OrderedDict
# Uncomment to do type checks. I have it commented out so it works below Python 3.5 # Uncomment to do type checks. I have it commented out so it works below Python 3.5
# from typing import List, Dict, TextIO, Tuple, Iterable, Optional, DefaultDict, Any, Union # from typing import List, Dict, TextIO, Tuple, Iterable, Optional, DefaultDict, Any, Union
# http(s)://docs.godotengine.org/<langcode>/<tag>/path/to/page.html(#fragment-tag) # $DOCS_URL/path/to/page.html(#fragment-tag)
GODOT_DOCS_PATTERN = re.compile( GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$")
r"^http(?:s)?://docs\.godotengine\.org/(?:[a-zA-Z0-9.\-_]*)/(?:[a-zA-Z0-9.\-_]*)/(.*)\.html(#.*)?$"
)
def print_error(error, state): # type: (str, State) -> None def print_error(error, state): # type: (str, State) -> None
@ -857,16 +855,11 @@ def rstize_text(text, state): # type: (str, State) -> str
# Handle [tags] # Handle [tags]
inside_code = False inside_code = False
inside_url = False
url_has_name = False
url_link = ""
pos = 0 pos = 0
tag_depth = 0 tag_depth = 0
previous_pos = 0 previous_pos = 0
while True: while True:
pos = text.find("[", pos) pos = text.find("[", pos)
if inside_url and (pos > previous_pos):
url_has_name = True
if pos == -1: if pos == -1:
break break
@ -995,17 +988,23 @@ def rstize_text(text, state): # type: (str, State) -> str
elif cmd.find("image=") == 0: elif cmd.find("image=") == 0:
tag_text = "" # '![](' + cmd[6:] + ')' tag_text = "" # '![](' + cmd[6:] + ')'
elif cmd.find("url=") == 0: elif cmd.find("url=") == 0:
url_link = cmd[4:] # URLs are handled in full here as we need to extract the optional link
tag_text = "`" # title to use `make_link`.
tag_depth += 1 link_url = cmd[4:]
inside_url = True endurl_pos = text.find("[/url]", endq_pos + 1)
url_has_name = False if endurl_pos == -1:
elif cmd == "/url": print_error(
tag_text = ("" if url_has_name else url_link) + " <" + url_link + ">`__" "Tag depth mismatch for [url]: no closing [/url], file: {}".format(state.current_class), state
tag_depth -= 1 )
escape_post = True break
inside_url = False link_title = text[endq_pos + 1 : endurl_pos]
url_has_name = False tag_text = make_link(link_url, link_title)
pre_text = text[:pos]
text = pre_text + tag_text + text[endurl_pos + 6 :]
pos = len(pre_text) + len(tag_text)
previous_pos = pos
continue
elif cmd == "center": elif cmd == "center":
tag_depth += 1 tag_depth += 1
tag_text = "" tag_text = ""
@ -1252,20 +1251,21 @@ def make_link(url, title): # type: (str, str) -> str
if match.lastindex == 2: if match.lastindex == 2:
# Doc reference with fragment identifier: emit direct link to section with reference to page, for example: # Doc reference with fragment identifier: emit direct link to section with reference to page, for example:
# `#calling-javascript-from-script in Exporting For Web` # `#calling-javascript-from-script in Exporting For Web`
return "`" + groups[1] + " <../" + groups[0] + ".html" + groups[1] + ">`_ in :doc:`../" + groups[0] + "`" # Or use the title if provided.
# Commented out alternative: Instead just emit: if title != "":
# `Subsection in Exporting For Web` return "`" + title + " <../" + groups[0] + ".html" + groups[1] + ">`__"
# return "`Subsection <../" + groups[0] + ".html" + groups[1] + ">`__ in :doc:`../" + groups[0] + "`" return "`" + groups[1] + " <../" + groups[0] + ".html" + groups[1] + ">`__ in :doc:`../" + groups[0] + "`"
elif match.lastindex == 1: elif match.lastindex == 1:
# Doc reference, for example: # Doc reference, for example:
# `Math` # `Math`
if title != "":
return ":doc:`" + title + " <../" + groups[0] + ">`"
return ":doc:`../" + groups[0] + "`" return ":doc:`../" + groups[0] + "`"
else: else:
# External link, for example: # External link, for example:
# `http://enet.bespin.org/usergroup0.html` # `http://enet.bespin.org/usergroup0.html`
if title != "": if title != "":
return "`" + title + " <" + url + ">`__" return "`" + title + " <" + url + ">`__"
else:
return "`" + url + " <" + url + ">`__" return "`" + url + " <" + url + ">`__"

View File

@ -33,13 +33,14 @@
#include "core/core_constants.h" #include "core/core_constants.h"
#include "core/input/input.h" #include "core/input/input.h"
#include "core/os/keyboard.h" #include "core/os/keyboard.h"
#include "core/version_generated.gen.h"
#include "doc_data_compressed.gen.h" #include "doc_data_compressed.gen.h"
#include "editor/plugins/script_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h"
#include "editor_node.h" #include "editor_node.h"
#include "editor_scale.h" #include "editor_scale.h"
#include "editor_settings.h" #include "editor_settings.h"
#define CONTRIBUTE_URL "https://docs.godotengine.org/en/latest/community/contributing/updating_the_class_reference.html" #define CONTRIBUTE_URL vformat("%s/community/contributing/updating_the_class_reference.html", VERSION_DOCS_URL)
DocTools *EditorHelp::doc = nullptr; DocTools *EditorHelp::doc = nullptr;

View File

@ -34,6 +34,7 @@
#include "core/io/resource_saver.h" #include "core/io/resource_saver.h"
#include "core/os/keyboard.h" #include "core/os/keyboard.h"
#include "core/os/os.h" #include "core/os/os.h"
#include "core/version_generated.gen.h"
#include "editor/editor_node.h" #include "editor/editor_node.h"
#include "editor/editor_scale.h" #include "editor/editor_scale.h"
#include "editor/editor_settings.h" #include "editor/editor_settings.h"
@ -384,7 +385,7 @@ void ShaderEditor::_menu_option(int p_option) {
shader_editor->remove_all_bookmarks(); shader_editor->remove_all_bookmarks();
} break; } break;
case HELP_DOCS: { case HELP_DOCS: {
OS::get_singleton()->shell_open("https://docs.godotengine.org/en/latest/tutorials/shaders/shader_reference/index.html"); OS::get_singleton()->shell_open(vformat("%s/tutorials/shaders/shader_reference/index.html", VERSION_DOCS_URL));
} break; } break;
} }
if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) { if (p_option != SEARCH_FIND && p_option != SEARCH_REPLACE && p_option != SEARCH_GOTO_LINE) {

View File

@ -38,6 +38,7 @@
#include "core/io/resource_saver.h" #include "core/io/resource_saver.h"
#include "core/os/os.h" #include "core/os/os.h"
#include "core/string/optimized_translation.h" #include "core/string/optimized_translation.h"
#include "core/version_generated.gen.h"
#include "editor_data.h" #include "editor_data.h"
#include "editor_node.h" #include "editor_node.h"
#include "editor_scale.h" #include "editor_scale.h"
@ -456,7 +457,7 @@ void ProjectExportDialog::_enc_filters_changed(const String &p_filters) {
} }
void ProjectExportDialog::_open_key_help_link() { void ProjectExportDialog::_open_key_help_link() {
OS::get_singleton()->shell_open("https://docs.godotengine.org/en/latest/development/compiling/compiling_with_script_encryption_key.html"); OS::get_singleton()->shell_open(vformat("%s/development/compiling/compiling_with_script_encryption_key.html", VERSION_DOCS_URL));
} }
void ProjectExportDialog::_enc_pck_changed(bool p_pressed) { void ProjectExportDialog::_enc_pck_changed(bool p_pressed) {

View File

@ -105,6 +105,8 @@ def update_version(module_version_string=""):
f.write('#define VERSION_MODULE_CONFIG "' + str(version.module_config) + module_version_string + '"\n') f.write('#define VERSION_MODULE_CONFIG "' + str(version.module_config) + module_version_string + '"\n')
f.write("#define VERSION_YEAR " + str(version.year) + "\n") f.write("#define VERSION_YEAR " + str(version.year) + "\n")
f.write('#define VERSION_WEBSITE "' + str(version.website) + '"\n') f.write('#define VERSION_WEBSITE "' + str(version.website) + '"\n')
f.write('#define VERSION_DOCS_BRANCH "' + str(version.docs) + '"\n')
f.write('#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH\n')
f.write("#endif // VERSION_GENERATED_GEN_H\n") f.write("#endif // VERSION_GENERATED_GEN_H\n")
f.close() f.close()

View File

@ -7,3 +7,4 @@ status = "dev"
module_config = "" module_config = ""
year = 2021 year = 2021
website = "https://godotengine.org" website = "https://godotengine.org"
docs = "latest"