From 5cbe0384934a6799b4ccfb7cb8b2141dd1e016a9 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Sun, 1 Mar 2026 15:32:21 +0000 Subject: [PATCH] Fix %-encoding in UriToFilePath In #1119 a change was made to "unquote" the URI before converting to a file path, ostensibly to support windows. It seems that in Python 3.14 the underlying issue this was working around was fixed, and as a result we're broken, leading to paths being truncated. The tests added for UriToFilePath with Windows paths still pass unchanged without the hack on Python 3.14 and the new test passes on pre-3.14 with the hack, so we have to gate it on version, sadly. --- .../language_server_protocol.py | 21 ++++++++++++------- .../language_server_protocol_test.py | 2 ++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ycmd/completers/language_server/language_server_protocol.py b/ycmd/completers/language_server/language_server_protocol.py index ef4bb4005a..e26ecfc336 100644 --- a/ycmd/completers/language_server/language_server_protocol.py +++ b/ycmd/completers/language_server/language_server_protocol.py @@ -15,6 +15,7 @@ # You should have received a copy of the GNU General Public License # along with ycmd. If not, see . +import sys import collections import os import json @@ -761,14 +762,18 @@ def UriToFilePath( uri ): if parsed_uri.scheme != 'file': raise InvalidUriException( uri ) - # url2pathname doesn't work as expected when uri.path is percent-encoded and - # is a windows path for ex: - # url2pathname('/C%3a/') == 'C:\\C:' - # whereas - # url2pathname('/C:/') == 'C:\\' - # Therefore first unquote pathname. - pathname = unquote( parsed_uri.path ) - return os.path.abspath( url2pathname( pathname ) ) + if sys.version_info < ( 3, 14 ): + # Before Python 3.14: + # url2pathname doesn't work as expected when uri.path is percent-encoded and + # is a windows path for ex: + # url2pathname('/C%3a/') == 'C:\\C:' + # whereas + # url2pathname('/C:/') == 'C:\\' + # Therefore first unquote pathname. + return os.path.abspath( url2pathname( unquote( parsed_uri.path ) ) ) + else: + # After Python 3.14, url2pathname seems to work properly + return os.path.abspath( url2pathname( uri, require_scheme=True ) ) def _BuildMessageData( message ): diff --git a/ycmd/tests/language_server/language_server_protocol_test.py b/ycmd/tests/language_server/language_server_protocol_test.py index 15c91a0001..4133bea0c3 100644 --- a/ycmd/tests/language_server/language_server_protocol_test.py +++ b/ycmd/tests/language_server/language_server_protocol_test.py @@ -153,6 +153,8 @@ def test_UriToFilePath_Unix( self ): equal_to( '/usr/local/test/test.test' ) ) assert_that( lsp.UriToFilePath( 'file:///usr/local/test/test.test' ), equal_to( '/usr/local/test/test.test' ) ) + assert_that( lsp.UriToFilePath( 'file:///usr/local/test%23foo/test.test' ), + equal_to( '/usr/local/test#foo/test.test' ) ) @WindowsOnly