4040from textual .css .constants import VALID_DISPLAY , VALID_VISIBILITY
4141from textual .css .errors import DeclarationError , StyleValueError
4242from textual .css .match import match
43- from textual .css .parse import parse_declarations , parse_selectors
43+ from textual .css .parse import is_id_selector , parse_declarations , parse_selectors
4444from textual .css .query import InvalidQueryFormat , NoMatches , TooManyMatches , WrongType
4545from textual .css .styles import RenderStyles , Styles
4646from textual .css .tokenize import IDENTIFIER
4949from textual .reactive import Reactive , ReactiveError , _Mutated , _watch
5050from textual .style import Style as VisualStyle
5151from textual .timer import Timer
52- from textual .walk import walk_breadth_first , walk_depth_first
52+ from textual .walk import walk_breadth_first , walk_breadth_search_id , walk_depth_first
5353from textual .worker_manager import WorkerManager
5454
5555if TYPE_CHECKING :
@@ -1466,6 +1466,26 @@ def query_one(
14661466 else :
14671467 query_selector = selector .__name__
14681468
1469+ if is_id_selector (query_selector ):
1470+ cache_key = (base_node ._nodes ._updates , query_selector , expect_type )
1471+ cached_result = base_node ._query_one_cache .get (cache_key )
1472+ if cached_result is not None :
1473+ return cached_result
1474+ if (
1475+ node := walk_breadth_search_id (
1476+ base_node , query_selector [1 :], with_root = False
1477+ )
1478+ ) is not None :
1479+ if expect_type is not None and not isinstance (node , expect_type ):
1480+ raise WrongType (
1481+ f"Node matching { query_selector !r} is the wrong type; expected type { expect_type .__name__ !r} , found { node } "
1482+ )
1483+ base_node ._query_one_cache [cache_key ] = node
1484+ return node
1485+ raise NoMatches (
1486+ f"No nodes match { query_selector !r} on { base_node !r} { list (base_node ._nodes )} "
1487+ )
1488+
14691489 try :
14701490 selector_set = parse_selectors (query_selector )
14711491 except TokenError :
@@ -1492,7 +1512,7 @@ def query_one(
14921512 base_node ._query_one_cache [cache_key ] = node
14931513 return node
14941514
1495- raise NoMatches (f"No nodes match { selector !r} on { base_node !r} " )
1515+ raise NoMatches (f"No nodes match { query_selector !r} on { base_node !r} " )
14961516
14971517 if TYPE_CHECKING :
14981518
@@ -1572,7 +1592,7 @@ def query_exactly_one(
15721592 base_node ._query_one_cache [cache_key ] = node
15731593 return node
15741594
1575- raise NoMatches (f"No nodes match { selector !r} on { base_node !r} " )
1595+ raise NoMatches (f"No nodes match { query_selector !r} on { base_node !r} " )
15761596
15771597 if TYPE_CHECKING :
15781598
0 commit comments