-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcli.py
More file actions
executable file
·211 lines (164 loc) · 6.69 KB
/
cli.py
File metadata and controls
executable file
·211 lines (164 loc) · 6.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#!/usr/bin/env python3
"""
Dictionary CLI - Search and manage dictionary terms
"""
import json
import sys
import argparse
import os
import re
DICTIONARY_FILE = "dictionary.json"
DEFAULT_DEFINITION = "I didn't get that"
def sanitize_text(text):
"""Remove or replace characters that could invalidate JSON"""
if not isinstance(text, str):
return str(text)
# Remove control characters except newlines and tabs
text = re.sub(r'[\x00-\x08\x0B-\x0C\x0E-\x1F]', '', text)
# Remove zero-width characters
text = text.replace('\u200b', '').replace('\u200c', '').replace('\u200d', '')
text = text.replace('\ufeff', '') # BOM
# Strip and normalize whitespace
text = text.strip()
return text
def validate_and_clean_dictionary():
"""Validate and clean the dictionary.json file on startup"""
if not os.path.exists(DICTIONARY_FILE):
return []
try:
# Try to load the JSON
with open(DICTIONARY_FILE, 'r', encoding='utf-8') as f:
content = f.read()
# Try to parse
json_fixed = False
try:
dictionary = json.loads(content)
except json.JSONDecodeError as e:
# Try to fix common JSON issues
print(f"Warning: JSON syntax error detected. Attempting to fix...", file=sys.stderr)
# Fix missing commas between objects in array
content = re.sub(r'}\s*\n\s*{', '},\n {', content)
# Fix trailing commas
content = re.sub(r',\s*}', '}', content)
content = re.sub(r',\s*]', ']', content)
try:
dictionary = json.loads(content)
print("Fixed JSON syntax errors.", file=sys.stderr)
json_fixed = True
except json.JSONDecodeError:
print(f"Error: Could not fix JSON. Please check the file manually. Error: {e}", file=sys.stderr)
return []
# Validate structure and sanitize content
if not isinstance(dictionary, list):
print("Error: Dictionary must be a JSON array.", file=sys.stderr)
return []
cleaned_dictionary = []
needs_save = json_fixed # Save if we fixed JSON syntax
for entry in dictionary:
if not isinstance(entry, dict):
continue
term = entry.get("term", "")
definition = entry.get("definition", "")
# Sanitize content
cleaned_term = sanitize_text(term)
cleaned_definition = sanitize_text(definition)
# Check if cleaning changed anything
if term != cleaned_term or definition != cleaned_definition:
needs_save = True
# Only add entries with non-empty term and definition
if cleaned_term and cleaned_definition:
cleaned_dictionary.append({
"term": cleaned_term,
"definition": cleaned_definition
})
# Remove duplicates (case-insensitive)
seen_terms = set()
unique_dictionary = []
for entry in cleaned_dictionary:
term_lower = entry["term"].lower()
if term_lower not in seen_terms:
seen_terms.add(term_lower)
unique_dictionary.append(entry)
else:
needs_save = True
# Save if we made changes
if needs_save or len(unique_dictionary) != len(dictionary):
save_dictionary(unique_dictionary)
if needs_save:
print("Cleaned and saved dictionary file.", file=sys.stderr)
return unique_dictionary
except (IOError, OSError) as e:
print(f"Error reading dictionary file: {e}", file=sys.stderr)
return []
def load_dictionary():
"""Load dictionary from JSON file"""
return validate_and_clean_dictionary()
def save_dictionary(dictionary):
"""Save dictionary to JSON file with proper formatting"""
with open(DICTIONARY_FILE, 'w', encoding='utf-8') as f:
json.dump(dictionary, f, indent=2, ensure_ascii=False)
f.write('\n') # Add newline at end of file
def search_term(term):
"""Search for a term in the dictionary"""
dictionary = load_dictionary()
term_lower = term.lower()
for entry in dictionary:
if entry.get("term", "").lower() == term_lower:
print(entry.get("definition", ""))
return True
print(f"Term '{term}' not found in dictionary.", file=sys.stderr)
return False
def add_term(term, definition):
"""Add a new term to the dictionary"""
dictionary = load_dictionary()
term_lower = term.lower()
# Check if term already exists
for entry in dictionary:
if entry.get("term", "").lower() == term_lower:
print(f"Term '{term}' already exists. Use a different term.", file=sys.stderr)
return False
# Apply default definition if empty or missing
if definition is None:
definition = DEFAULT_DEFINITION
else:
definition = sanitize_text(definition)
if not definition:
definition = DEFAULT_DEFINITION
# Add new entry
dictionary.append({
"term": term,
"definition": definition
})
save_dictionary(dictionary)
print(f"Added term '{term}' to dictionary.")
return True
def main():
# Validate and clean dictionary on startup
validate_and_clean_dictionary()
parser = argparse.ArgumentParser(
description="Dictionary CLI - Search and manage dictionary terms",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python cli.py hello # Search for term 'hello'
python cli.py --term "world" --definition "the earth" # Add new term
"""
)
parser.add_argument('term', nargs='?', help='Term to search for')
parser.add_argument('--term', dest='add_term', help='Term to add (definition is optional)')
parser.add_argument('--definition', help=f'Definition for the term (defaults to "{DEFAULT_DEFINITION}" when omitted)')
args = parser.parse_args()
# If --term is provided, add term (definition optional)
if args.add_term is not None:
term_to_add = sanitize_text(args.add_term)
definition_to_add = args.definition
add_term(term_to_add, definition_to_add)
# If a positional term is provided, search for it
elif args.term:
success = search_term(args.term)
sys.exit(0 if success else 1)
# Otherwise show help
else:
parser.print_help()
if __name__ == "__main__":
main()