11from dataclasses import dataclass
2+ from typing import Literal
23
34import plain_spec
45from plain2code_exceptions import ModuleDoesNotExistError
@@ -10,7 +11,7 @@ class PartialRender:
1011 last_render_module : PlainModule
1112 last_render_frid : str | None
1213 change : PlainModule | None = None
13- change_type : str | None = None
14+ change_type : Literal [ "spec_change" , "code_change" ] | None = None
1415
1516
1617@dataclass
@@ -21,43 +22,27 @@ class PartialRenderChoice:
2122
2223
2324def spec_change (plain_module : PlainModule ) -> PlainModule | None :
24- for required_module in plain_module .all_required_modules :
25- module_metadata = required_module .load_module_metadata ()
25+ all_modules = plain_module .all_required_modules + [plain_module ]
26+ for _module in all_modules :
27+ module_metadata = _module .load_module_metadata ()
2628 if (
2729 module_metadata
2830 and "source_hash" in module_metadata
29- and module_metadata ["source_hash" ] != required_module .get_module_source_hash ()
31+ and module_metadata ["source_hash" ] != _module .get_module_source_hash ()
3032 ):
31- return required_module
32-
33- module_metadata = plain_module .load_module_metadata ()
34- if (
35- module_metadata
36- and "source_hash" in module_metadata
37- and module_metadata ["source_hash" ] != plain_module .get_module_source_hash ()
38- ):
39- return plain_module
33+ return _module
4034
4135 return None
4236
4337
4438def code_change (plain_module : PlainModule ) -> PlainModule | None :
45- for required_module in plain_module .all_required_modules :
46- if len (required_module .required_modules ) == 0 :
39+ all_modules = plain_module .all_required_modules + [plain_module ]
40+ for _module in all_modules :
41+ if len (_module .required_modules ) == 0 :
4742 continue
4843
49- module_metadata = required_module .load_module_metadata ()
50- previous_module = required_module .required_modules [- 1 ]
51- if (
52- module_metadata
53- and "required_modules_code_hash" in module_metadata
54- and module_metadata ["required_modules_code_hash" ] != previous_module .get_module_code_hash ()
55- ):
56- return previous_module
57-
58- module_metadata = plain_module .load_module_metadata ()
59- if len (plain_module .required_modules ) > 0 :
60- previous_module = plain_module .required_modules [- 1 ]
44+ module_metadata = _module .load_module_metadata ()
45+ previous_module = _module .required_modules [- 1 ]
6146 if (
6247 module_metadata
6348 and "required_modules_code_hash" in module_metadata
@@ -68,7 +53,7 @@ def code_change(plain_module: PlainModule) -> PlainModule | None:
6853 return None
6954
7055
71- def module_comes_before (
56+ def module_comes_before_or_equal (
7257 all_required_modules : list [PlainModule ],
7358 module1 : PlainModule ,
7459 module2 : PlainModule ,
@@ -87,16 +72,11 @@ def detect_partial_rendering(plain_module: PlainModule) -> PartialRender | None:
8772 sc = spec_change (plain_module )
8873 cc = code_change (plain_module )
8974 all_required_modules = plain_module .all_required_modules
90- last_rendered_module , last_rendered_frid = plain_module .get_last_rendered_frid ()
91- if last_rendered_module is None and last_rendered_frid is None :
75+ last_rendered_module_name , last_rendered_frid = plain_module .get_module_last_rendered_functionality ()
76+ if last_rendered_module_name is None and last_rendered_frid is None :
9277 return None
9378
94- module = None
95- for required_module in all_required_modules :
96- if required_module .module_name == last_rendered_module :
97- module = required_module
98-
99- if last_rendered_module == plain_module .module_name :
79+ if last_rendered_module_name == plain_module .module_name :
10080 if (
10181 last_rendered_frid is None
10282 or plain_spec .get_next_frid (plain_module .plain_source , last_rendered_frid ) is not None
@@ -105,9 +85,14 @@ def detect_partial_rendering(plain_module: PlainModule) -> PartialRender | None:
10585 else :
10686 return None
10787
88+ module = None
89+ for required_module in all_required_modules :
90+ if required_module .module_name == last_rendered_module_name :
91+ module = required_module
92+
10893 if module is None :
10994 raise ModuleDoesNotExistError (
110- f"Last rendered module { last_rendered_module } not found in { [rmodule .module_name for rmodule in all_required_modules ]} "
95+ f"Last rendered module { last_rendered_module_name } not found in { [rmodule .module_name for rmodule in all_required_modules ]} "
11196 )
11297
11398 pr = PartialRender (
@@ -125,9 +110,73 @@ def detect_partial_rendering(plain_module: PlainModule) -> PartialRender | None:
125110 pr .change_type = "spec_change"
126111
127112 if cc is not None and (
128- pr .change is None or (pr .change is not None and module_comes_before (all_required_modules , cc , pr .change ))
113+ pr .change is None
114+ or (pr .change is not None and module_comes_before_or_equal (all_required_modules , cc , pr .change ))
129115 ):
130116 pr .change = cc
131117 pr .change_type = "code_change"
132118
133119 return pr
120+
121+
122+ def get_choices (plain_module : PlainModule , partial_render : PartialRender ) -> dict [str , PartialRenderChoice ]:
123+ choices = dict [str , PartialRenderChoice ]()
124+ choice_idx = 1
125+ if not partial_render .last_render_module .is_module_fully_rendered ():
126+ choices [str (choice_idx )] = PartialRenderChoice (
127+ module = partial_render .last_render_module ,
128+ render_range = None ,
129+ msg = f"Start from module [#5593FF]{ partial_render .last_render_module .module_name } [/]" ,
130+ )
131+ choice_idx += 1
132+ if not partial_render .last_render_module .is_initial_module ():
133+ if not partial_render .last_render_frid :
134+ raise ValueError ("Last render FRID is not set for a non-initial module" )
135+
136+ next_frid , next_module = plain_module .get_next_frid (
137+ partial_render .last_render_frid , partial_render .last_render_module .module_name
138+ )
139+ render_range = plain_spec .get_render_range_from (next_frid , next_module .plain_source )
140+ msg = "Continue from"
141+ if next_frid != plain_spec .get_first_frid (next_module .plain_source ):
142+ msg += f" functionality [#5593FF]{ next_frid } [/]"
143+ else :
144+ msg += f" module [#5593FF]{ next_module .module_name } [/]"
145+
146+ choices [str (choice_idx )] = PartialRenderChoice (
147+ module = next_module ,
148+ render_range = render_range ,
149+ msg = msg ,
150+ )
151+ choice_idx += 1
152+
153+ if partial_render .change :
154+ all_affected_modules = list [str ]()
155+ affected_module = False
156+ for module in plain_module .all_required_modules :
157+ if module .module_name == partial_render .change .module_name :
158+ affected_module = True
159+ if affected_module :
160+ all_affected_modules .append (module .module_name )
161+
162+ choices [str (choice_idx )] = PartialRenderChoice (
163+ module = partial_render .change ,
164+ render_range = None ,
165+ msg = f"Re-render all affected modules ([#5593FF]{ ', ' .join (all_affected_modules )} [/])" ,
166+ )
167+ choice_idx += 1
168+
169+ first_module = plain_module .all_required_modules [0 ]
170+ if first_module .module_name != partial_render .last_render_module .module_name and (
171+ partial_render .change is not None and first_module .module_name != partial_render .change .module_name
172+ ):
173+ choices [str (choice_idx )] = PartialRenderChoice (
174+ module = first_module ,
175+ render_range = None ,
176+ msg = f"Re-render from first module ([#5593FF]{ first_module .module_name } [/])" ,
177+ )
178+ choice_idx += 1
179+
180+ choices [str (choice_idx )] = PartialRenderChoice (module = None , render_range = None , msg = "Quit" )
181+
182+ return choices
0 commit comments