@@ -48,7 +48,7 @@ def __init__(
4848 ]
4949 if source_locations :
5050 command .append ("--source-refname=master" )
51- command += crystal_docs_flags
51+ command += ( s . format_map ( _crystal_info ) for s in crystal_docs_flags )
5252 log .debug ("Running `%s`" , " " .join (shlex .quote (arg ) for arg in command ))
5353
5454 self ._proc = subprocess .Popen (command , stdout = subprocess .PIPE )
@@ -129,18 +129,12 @@ class _SourceDestination:
129129 def substitute (self , location : DocLocation ) -> str :
130130 data = {"file" : location .filename [len (self .src_path ) :], "line" : location .line }
131131 try :
132- return self .dest_url .format_map (collections .ChainMap (data , self )) # type: ignore
132+ return self .dest_url .format_map (collections .ChainMap (data , _DictAccess ( self ), _crystal_info )) # type: ignore
133133 except KeyError as e :
134134 raise PluginError (
135135 f"The source_locations template { self .dest_url !r} did not resolve correctly: { e } "
136136 )
137137
138- def __getitem__ (self , key ):
139- try :
140- return getattr (self , key )
141- except AttributeError as e :
142- raise KeyError (str (e ))
143-
144138 @property
145139 def shard_version (self ):
146140 return self ._shard_version (os .path .dirname (self .src_path ))
@@ -165,6 +159,36 @@ def _find_above(path: str, filename: str) -> str:
165159 raise PluginError (f"{ filename !r} not found anywhere above { os .path .abspath (orig_path )!r} " )
166160
167161
162+ class _CrystalInfo :
163+ @cached_property
164+ def crystal_version (self ) -> str :
165+ return subprocess .check_output (
166+ ["crystal" , "env" , "CRYSTAL_VERSION" ], encoding = "ascii"
167+ ).rstrip ()
168+
169+ @cached_property
170+ def crystal_src (self ):
171+ out = subprocess .check_output (["crystal" , "env" , "CRYSTAL_PATH" ], text = True ).rstrip ()
172+ for path in out .split (os .pathsep ):
173+ if os .path .isfile (os .path .join (path , "prelude.cr" )):
174+ return os .path .relpath (path )
175+ raise PluginError (f"Crystal sources not found anywhere in CRYSTAL_PATH={ out !r} " )
176+
177+
178+ class _DictAccess :
179+ def __init__ (self , obj ):
180+ self .obj = obj
181+
182+ def __getitem__ (self , key ):
183+ try :
184+ return getattr (self .obj , key )
185+ except AttributeError as e :
186+ raise KeyError (f"Missing key: { e } " )
187+
188+
189+ _crystal_info = _DictAccess (_CrystalInfo ())
190+
191+
168192class DocRoot (DocModule ):
169193 source_locations : List [_SourceDestination ]
170194
0 commit comments