Skip to content

Commit a4461ec

Browse files
authored
Merge pull request #168 from Integration-Automation/dev
Dev
2 parents c3a9b29 + 4ea4ba6 commit a4461ec

34 files changed

+1778
-71
lines changed

.idea/discord.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dev.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ build-backend = "setuptools.build_meta"
66

77
[project]
88
name = "je_editor_dev"
9-
version = "0.0.231"
9+
version = "0.0.236"
1010
authors = [
1111
{ name = "JE-Chen", email = "[email protected]" },
1212
]
1313
description = "JEditor is basic but powerful editor include GPT"
1414
requires-python = ">=3.10"
1515
license-files = ["LICENSE"]
1616
dependencies = [
17-
"PySide6==6.9.1", "qt-material", "yapf", "frontengine", "pycodestyle", "jedi",
18-
"qtconsole", "langchain_openai", "langchain", "pydantic"
17+
"PySide6==6.9.2", "qt-material", "yapf", "frontengine", "pycodestyle", "jedi",
18+
"qtconsole", "langchain_openai", "langchain", "pydantic", "watchdog", "ruff"
1919
]
2020
classifiers = [
2121
"Programming Language :: Python :: 3.10",
@@ -37,4 +37,4 @@ content-type = "text/markdown"
3737

3838

3939
[tool.setuptools.packages]
40-
find = { namespaces = false }
40+
find = { namespaces = false }

exe/a.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
print("Hello World")
2+
print(var)

exe/start_editor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
from je_editor.start_editor import start_editor
1+
from je_editor import start_editor
22

33
start_editor()

je_editor/code_scan/__init__.py

Whitespace-only changes.

je_editor/code_scan/ruff_thread.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import subprocess
2+
import threading
3+
import time
4+
from queue import Queue
5+
6+
7+
class RuffThread(threading.Thread):
8+
9+
def __init__(self, ruff_commands: list, std_queue: Queue, stderr_queue: Queue):
10+
super().__init__()
11+
if ruff_commands is None:
12+
self.ruff_commands = ["ruff", "check"]
13+
else:
14+
self.ruff_commands = ruff_commands
15+
self.ruff_process = None
16+
self.std_queue = std_queue
17+
self.stderr_queue = stderr_queue
18+
19+
def run(self):
20+
self.ruff_process = subprocess.Popen(
21+
self.ruff_commands, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1)
22+
while self.ruff_process.poll() is None:
23+
time.sleep(1)
24+
else:
25+
for line in self.ruff_process.stdout:
26+
print(line.strip())
27+
for line in self.ruff_process.stderr:
28+
print(line.strip())
29+
30+
31+
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from queue import Queue
2+
3+
from watchdog.events import FileSystemEventHandler
4+
5+
from je_editor.code_scan.ruff_thread import RuffThread
6+
7+
8+
class RuffPythonFileChangeHandler(FileSystemEventHandler):
9+
10+
def __init__(self, ruff_commands: list = None):
11+
super(RuffPythonFileChangeHandler, self).__init__()
12+
self.ruff_commands = ruff_commands
13+
self.stdout_queue = Queue()
14+
self.stderr_queue = Queue()
15+
self.ruff_threads_dict = dict()
16+
17+
def on_modified(self, event):
18+
if event.is_directory:
19+
return
20+
if event.src_path.endswith(".py"):
21+
if self.ruff_threads_dict.get(event.src_path) is None:
22+
ruff_thread = RuffThread(self.ruff_commands, self.stdout_queue, self.stderr_queue)
23+
self.ruff_threads_dict.update({event.src_path: ruff_thread})
24+
ruff_thread.start()
25+
else:
26+
ruff_thread = self.ruff_threads_dict.get(event.src_path)
27+
if not ruff_thread.is_alive():
28+
ruff_thread = RuffThread(self.ruff_commands, self.stdout_queue, self.stderr_queue)
29+
self.ruff_threads_dict.update({event.src_path: ruff_thread})
30+
ruff_thread.start()
31+
else:
32+
pass
33+
34+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import threading
2+
import time
3+
4+
from watchdog.observers import Observer
5+
6+
from je_editor.code_scan.watchdog_implement import RuffPythonFileChangeHandler
7+
8+
9+
class WatchdogThread(threading.Thread):
10+
11+
def __init__(self, check_path: str):
12+
super().__init__()
13+
self.check_path = check_path
14+
self.ruff_handler = RuffPythonFileChangeHandler()
15+
self.running = True
16+
17+
def run(self):
18+
observer = Observer()
19+
observer.schedule(self.ruff_handler, str(self.check_path), recursive=True)
20+
observer.start()
21+
try:
22+
while self.running:
23+
time.sleep(1)
24+
finally:
25+
observer.stop()
26+
27+
28+
if __name__ == '__main__':
29+
watchdog_thread = WatchdogThread("")
30+
watchdog_thread.start()
31+
while True:
32+
time.sleep(1)
33+

je_editor/git_client/__init__.py

Whitespace-only changes.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import logging
2+
from dataclasses import dataclass, field
3+
from typing import List, Dict
4+
5+
log = logging.getLogger(__name__)
6+
7+
8+
@dataclass
9+
class CommitNode:
10+
commit_sha: str
11+
author_name: str
12+
commit_date: str
13+
commit_message: str
14+
parent_shas: List[str]
15+
lane_index: int = -1 # assigned later
16+
17+
@dataclass
18+
class CommitGraph:
19+
nodes: List[CommitNode] = field(default_factory=list)
20+
index: Dict[str, int] = field(default_factory=dict) # sha -> row
21+
22+
def build(self, commits: List[Dict], refs: Dict[str, str]) -> None:
23+
# commits are topo-ordered by git_client log --topo-order; we keep it.
24+
self.nodes = [
25+
CommitNode(
26+
commit_sha=c["sha"],
27+
author_name=c["author"],
28+
commit_date=c["date"],
29+
commit_message=c["message"],
30+
parent_shas=c["parents"],
31+
) for c in commits
32+
]
33+
self.index = {n.commit_sha: i for i, n in enumerate(self.nodes)}
34+
self._assign_lanes()
35+
36+
def _assign_lanes(self) -> None:
37+
"""
38+
Simple lane assignment similar to 'git_client log --graph' lanes.
39+
Greedy: reuse freed lanes; parents may create new lanes.
40+
"""
41+
active: Dict[int, str] = {} # lane -> sha
42+
free_lanes: List[int] = []
43+
44+
for i, node in enumerate(self.nodes):
45+
# If any active lane points to this commit, use that lane
46+
lane_found = None
47+
for lane, sha in list(active.items()):
48+
if sha == node.commit_sha:
49+
lane_found = lane
50+
break
51+
52+
if lane_found is None:
53+
if free_lanes:
54+
node.lane_index = free_lanes.pop(0)
55+
else:
56+
node.lane_index = 0 if not active else max(active.keys()) + 1
57+
else:
58+
node.lane_index = lane_found
59+
60+
# Update active: current node consumes its lane, parents occupy lanes
61+
# Remove the current sha from any lane that pointed to it
62+
for lane, sha in list(active.items()):
63+
if sha == node.commit_sha:
64+
del active[lane]
65+
66+
# First parent continues in the same lane; others go to free/new lanes
67+
if node.parent_shas:
68+
first = node.parent_shas[0]
69+
active[node.lane_index] = first
70+
# Side branches
71+
for p in node.parent_shas[1:]:
72+
# Pick a free lane or new one
73+
if free_lanes:
74+
pl = free_lanes.pop(0)
75+
else:
76+
pl = 0 if not active else max(active.keys()) + 1
77+
active[pl] = p
78+
79+
# Any lane whose target no longer appears in the future will be freed later
80+
# We approximate by freeing lanes when a target didn't appear in the next rows;
81+
# but for minimal viable, free when lane not reassigned by parents this row.
82+
used_lanes = set(active.keys())
83+
# Collect gaps below max lane as free lanes to reuse
84+
max_lane = max(used_lanes) if used_lanes else -1
85+
present = set(range(max_lane + 1))
86+
missing = sorted(list(present - used_lanes))
87+
# Merge missing into free_lanes maintaining order
88+
free_lanes = sorted(set(free_lanes + missing))

0 commit comments

Comments
 (0)