forked from Shinonome/dots-hyprland
add config file updater
This commit is contained in:
@@ -1,3 +1,6 @@
|
|||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
|
||||||
export function parseJSONC(jsoncString) {
|
export function parseJSONC(jsoncString) {
|
||||||
let result = "";
|
let result = "";
|
||||||
let inString = false;
|
let inString = false;
|
||||||
|
|||||||
Executable
+137
@@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/env -S\_/bin/sh\_-c\_"source\_\$(eval\_echo\_\$ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate&&exec\_python\_-E\_"\$0"\_"\$@""
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import ast
|
||||||
|
import re
|
||||||
|
|
||||||
|
def parse_value(value):
|
||||||
|
"""Parse the value into its appropriate Python type (e.g., bool, int, float, list, dict, or string)."""
|
||||||
|
try:
|
||||||
|
return ast.literal_eval(value)
|
||||||
|
except (ValueError, SyntaxError):
|
||||||
|
return value # Fallback to string if parsing fails
|
||||||
|
|
||||||
|
def remove_trailing_commas(json_string):
|
||||||
|
"""Remove trailing commas from JSON-like structures."""
|
||||||
|
return re.sub(r',\s*([\}\]])', r'\1', json_string)
|
||||||
|
|
||||||
|
def strip_comments_except_leading(lines):
|
||||||
|
"""
|
||||||
|
Removes all `//` and `/* ... */` comments, except for leading `//` comments at the start.
|
||||||
|
Ensures `//` inside strings is preserved.
|
||||||
|
Returns (preserved_comments, cleaned_json).
|
||||||
|
"""
|
||||||
|
preserved_comments = []
|
||||||
|
json_lines = []
|
||||||
|
in_block_comment = False
|
||||||
|
in_string = False
|
||||||
|
escaped = False
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
stripped = line.strip()
|
||||||
|
|
||||||
|
# Handle block comments
|
||||||
|
if in_block_comment:
|
||||||
|
if "*/" in stripped:
|
||||||
|
in_block_comment = False
|
||||||
|
continue
|
||||||
|
if stripped.startswith("/*"):
|
||||||
|
in_block_comment = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Preserve leading `//` comments at the very start
|
||||||
|
if stripped.startswith("//") and not json_lines:
|
||||||
|
preserved_comments.append(line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Process line while tracking if inside a string
|
||||||
|
new_line = []
|
||||||
|
i = 0
|
||||||
|
while i < len(line):
|
||||||
|
char = line[i]
|
||||||
|
|
||||||
|
if char == '"' or char == "'": # Detect string start
|
||||||
|
if not in_string:
|
||||||
|
in_string = char
|
||||||
|
elif in_string == char and not escaped:
|
||||||
|
in_string = False
|
||||||
|
elif char == "\\" and in_string: # Handle escape sequences
|
||||||
|
escaped = not escaped
|
||||||
|
else:
|
||||||
|
escaped = False
|
||||||
|
|
||||||
|
# Remove inline `//` comments only if not inside a string
|
||||||
|
if char == "/" and i + 1 < len(line) and line[i + 1] == "/" and not in_string:
|
||||||
|
break # Stop processing the line at `//` (comment start)
|
||||||
|
|
||||||
|
new_line.append(char)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
cleaned_line = "".join(new_line).rstrip()
|
||||||
|
if cleaned_line:
|
||||||
|
json_lines.append(cleaned_line + "\n")
|
||||||
|
|
||||||
|
return preserved_comments, json_lines
|
||||||
|
|
||||||
|
def update_json(file_path, key, value=None, reset=False):
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r') as file:
|
||||||
|
lines = file.readlines()
|
||||||
|
|
||||||
|
# Separate leading comments and clean JSON
|
||||||
|
preserved_comments, json_lines = strip_comments_except_leading(lines)
|
||||||
|
json_string = "".join(json_lines)
|
||||||
|
json_string = remove_trailing_commas(json_string)
|
||||||
|
|
||||||
|
# Convert the cleaned string into a JSON object
|
||||||
|
try:
|
||||||
|
json_data = json.loads(json_string)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
print(f"Error decoding JSON in file: {file_path}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Navigate through the key (e.g., 'search.enableFeatures.actions')
|
||||||
|
keys = key.split('.')
|
||||||
|
data = json_data
|
||||||
|
for k in keys[:-1]:
|
||||||
|
data = data.setdefault(k, {})
|
||||||
|
|
||||||
|
# Update or delete the key
|
||||||
|
if reset:
|
||||||
|
if keys[-1] in data:
|
||||||
|
del data[keys[-1]]
|
||||||
|
print(f"Successfully removed {key} from {file_path}")
|
||||||
|
else:
|
||||||
|
print(f"Key {key} not found in {file_path}")
|
||||||
|
else:
|
||||||
|
data[keys[-1]] = value
|
||||||
|
print(f"Successfully updated {key} to {value} in {file_path}")
|
||||||
|
|
||||||
|
# Write back only valid JSON (with preserved leading comments)
|
||||||
|
with open(file_path, 'w') as file:
|
||||||
|
file.writelines(preserved_comments) # Restore leading comments
|
||||||
|
json.dump(json_data, file, indent=4)
|
||||||
|
file.write("\n") # Ensure a newline at the end
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"File not found: {file_path}")
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {str(e)}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description="Update or remove a key from a JSON configuration file")
|
||||||
|
parser.add_argument('--key', required=True, help="The key to be updated or removed (e.g., 'search.enableFeatures.actions')")
|
||||||
|
parser.add_argument('--file', required=True, help="The path to the target JSON file")
|
||||||
|
parser.add_argument('--value', help="The new value to assign (e.g., 'true', '42', '[1, 2, 3]')")
|
||||||
|
parser.add_argument('--reset', action='store_true', help="If set, the key will be removed from the JSON file")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
value = None
|
||||||
|
if args.value:
|
||||||
|
value = parse_value(args.value)
|
||||||
|
|
||||||
|
update_json(args.file, args.key, value, reset=args.reset)
|
||||||
@@ -5,12 +5,13 @@
|
|||||||
// vim: `:vsp` to split window, move cursor to the path, press `gf`.
|
// vim: `:vsp` to split window, move cursor to the path, press `gf`.
|
||||||
// `Ctrl-w` twice to switch between the files
|
// `Ctrl-w` twice to switch between the files
|
||||||
//
|
//
|
||||||
// This file is parsed with a custom JSONC parser.
|
// Limitations of this file
|
||||||
// Don't expect every JSONC feature in... say, vscode, to work.
|
// Don't expect every JSONC feature in... say, vscode, to work.
|
||||||
|
// You can only have comments on top of the file
|
||||||
|
//
|
||||||
|
// Example: Put this to show 8 (instead of 10) workspaces on the bar
|
||||||
|
// "workspaces": {"shown": 8 }
|
||||||
|
//
|
||||||
{
|
{
|
||||||
// Example: Uncomment the following 3 lines to show 8 (instead of 10) workspaces on the bar
|
|
||||||
// "workspaces": {
|
|
||||||
// "shown": 8
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user