diff --git a/README.md b/README.md index 187fb51..78346d5 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ nix run 'github:max-amb/nix-tree' ## Limitations This program obviously is not perfect, hence there are some limitations that should be taken into account by the user: * The program cannot currently parse the `let in` combination or any flake for that matter -* The syntax "..." = ..., often found in home manager is not supported +* ~~The syntax "..." = ..., often found in home manager is not supported~~ Now is after some more complex regex matching * One example that doesn't work is code that has groups inside of sections, like `[ { ... } ]`, this will break the program for now * ~~It may not be able to handle multiline strings often found in `extraConfig` options~~ The program can take them as input but has no way of displaying different lines or outputting different lines * Comments done with `/* */` aren't stored for re-attachment as they are often inside clauses @@ -73,3 +73,4 @@ This program obviously is not perfect, hence there are some limitations that sho ## Credits * The test configuration `./tests/example_configurations/pms_example_config.nix` comes from [here](https://perfectmediaserver.com/02-tech-stack/nixos/configuration.nix/) * The test configuration `./tests/example_configurations/yasu_example_config.nix` comes from [here](https://discourse.nixos.org/t/configuration-nix-home-nix-examples/8185) +* The test configuration `./tests/example_configurations/shortened_default.nix` comes from the default nix configuration diff --git a/nix_tree/decomposer.py b/nix_tree/decomposer.py index 934fdc2..330027b 100644 --- a/nix_tree/decomposer.py +++ b/nix_tree/decomposer.py @@ -191,7 +191,7 @@ def __managing_headers(self) -> None: self.__tree.add_branch(contents=f"headers=[ {', '.join(headers)} ]") def __connecting_spaced_lines(self, file: list[str], iterator: int) -> tuple[list[str], int]: - if re.search(r"^''(?!.*''$).*", file[iterator]): + if re.search(r"^''(?!.*'').*", file[iterator]): j = iterator + 1 while j < len(file): file[iterator] += " " + file[j] @@ -200,7 +200,7 @@ def __connecting_spaced_lines(self, file: list[str], iterator: int) -> tuple[lis del file[j] break del file[j] - elif re.search(r'^"(?!.*"$).*', file[iterator]): + elif re.search(r'^"(?!.*").*', file[iterator]): j = iterator + 1 while j < len(file): file[iterator] += " " + file[j] @@ -350,14 +350,14 @@ def __cleaning_the_configuration(self, file: str) -> str: Returns: file: str - the file all on one line now cleaned """ - file = re.sub(r"[^\S\n]+", " ", file) + file = re.sub(r"[^\S\n]+", " ", file) # The [^\S\n] is my form of .*, it just excludes new lines so comment attaching can work as expected file = re.sub("=", " = ", file) file = re.sub(r"[^\S\n]}", " } ", file) file = re.sub(r"[^\S\n]{", " { ", file) file = re.sub(";", " ; ", file) # For with clauses file = re.sub(r"}[^\S\n]*;", "}; ", file) file = re.sub(r"][^\S\n]*;", "]; ", file) - file = re.sub(r'\[[^\S\n]*"', '[ "', file) + file = re.sub(r'\[[^\S\n]*"', '[ "', file) # Looks scary because of escapes for square brackets, is simply removing and adding spaces in lists file = re.sub(r"\[[^\S\n]*'", "[ '", file) file = re.sub(r"\[[^\S\n]*''", "[ ''", file) file = re.sub(r"(\S*)(];)", r"\1 \2", file) diff --git a/nix_tree/section_screens.py b/nix_tree/section_screens.py index a02bf7e..ef5afcd 100644 --- a/nix_tree/section_screens.py +++ b/nix_tree/section_screens.py @@ -325,7 +325,7 @@ def handle_return_from_variable_addition(data: tuple[str, Types | None] | None) else: self.app.pop_screen() - if re.search(r"[^a-zA-Z_.]", path.value): + if re.search(r"[^a-zA-Z_.'\"]", path.value): self.notify("You have entered invalid character(s) for the path of your option, not adding", title="error adding option", severity="error") self.dismiss(None) else: diff --git a/nix_tree/ui.py b/nix_tree/ui.py index e25e474..c9b6861 100644 --- a/nix_tree/ui.py +++ b/nix_tree/ui.py @@ -202,19 +202,23 @@ def __extract_data_from_action(self, action: str) -> tuple[str, str, str]: variable = "" path = "" if "[" in action: # List types - if match := re.search(r"(Added|Delete|Change) (.*)\[(.*)]", action): + if match := re.search(r"(Added|Delete|Change) (.*)\[(.*)]( type: Types.(STRING|BOOL|UNIQUE|LIST|INT))?$", action): path = match.group(2)[:-1] variable = "[" + match.group(3) + "]" else: raise ErrorComposingFileFromTree(message="Was unable to parse actions to apply to tree") full_path = path + "=" + variable elif "'" in action: # Any of the string types - if match := re.search(r"(Added|Delete|Change) (.*)''(.*)''", action): + if match := re.search(r"(Added|Delete|Change) (.*)''(.*?)''( type: Types.(STRING|BOOL|UNIQUE|LIST|INT))?$", action): path = match.group(2)[:-1] variable = "''" + match.group(3) + "''" - elif match := re.search(r"(Added|Delete|Change) (.*)'(.*)'", action): + elif match := re.search(r"(Added|Delete|Change) (.*)'(.*?)'( type: Types.(STRING|BOOL|UNIQUE|LIST|INT))?$", action): + # The 3rd group is non greedy to make a.'b'.c = 'x' paths work path = match.group(2)[:-1] variable = "'" + match.group(3) + "'" + elif match := re.search(r"(Added|Delete|Change) (.*)=(.*)( type: Types.(STRING|BOOL|UNIQUE|LIST|INT))?$", action): # String path but not string var like a.'b'.c = true + path = match.group(2) + variable = match.group(3) else: raise ErrorComposingFileFromTree(message="Was unable to parse actions to apply to tree") full_path = path + "=" + variable @@ -236,9 +240,9 @@ def action_undo(self, empty_command: bool = False) -> None: self.query_one("#operations_stack", ListView).pop(0) action: str | None = self.__stack.pop().name if action: - path, variable, full_path = self.__extract_data_from_action(action) match action.split(" ")[0]: case "Delete": + path, variable, full_path = self.__extract_data_from_action(action) var_type = None match action.split(" ")[-1]: case "Types.LIST": @@ -262,6 +266,7 @@ def action_undo(self, empty_command: bool = False) -> None: else: raise TypeError("Cannot deduce node variable type") case "Added": + path, variable, full_path = self.__extract_data_from_action(action) node_to_delete: UIVariableNode | None = self.recursive_searching_for_var( self.query_one(Tree).root, path.split("."), @@ -272,6 +277,7 @@ def action_undo(self, empty_command: bool = False) -> None: else: raise NodeNotFound(node_name=full_path) case "Change": + path, variable, full_path = self.__extract_data_from_action(action) change_command: str = action[7:] # Can't use space splits as it changes the lists spaces pre: list = change_command.split("->")[0].strip().split("=") post: list = change_command.split("->")[1].strip().split("=") @@ -335,14 +341,14 @@ def __apply_changes(self) -> None: while self.__queue.get_len() > 0: action = self.__queue.dequeue().name if action: - # This section is pulling all the data from the action such as the path of the option and the data - _, _, full_path = self.__extract_data_from_action(action) # Performing the operations on the tree match action.split(" ")[0]: case "Added": + _, _, full_path = self.__extract_data_from_action(action) tree.add_branch(full_path) case "Delete": + _, _, full_path = self.__extract_data_from_action(action) parent: Node | None = tree.find_node_parent(full_path, tree.get_root()) if parent: if isinstance(parent, ConnectorNode): @@ -352,6 +358,7 @@ def __apply_changes(self) -> None: else: raise NodeNotFound(node_name=full_path) case "Change": + _, _, full_path = self.__extract_data_from_action(action) change_command: str = action[7:] pre: str = change_command.split("->")[0].strip() post: str = change_command.split("->")[1].strip()