Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 26 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Download from the store
## Supported programs

- [x] visual studio code
- [x] visual studio
- [x] pycharm
- [x] clion
- [x] goland
Expand All @@ -24,17 +25,18 @@ You can access different programs using the following acronyms:

```json
{
"vsc": "VSCODE",
"py": "PYCHARM",
"cl": "CLION",
"go": "GOLAND",
"idea": "INTELLIJ_IDEA",
"as": "ANDROID_STUDIO",
"cur":"CURSOR",
"pdf":"SUMATRA_PDF",
"trae":"TRAE",
"vscs":"VSCODE_SSH",
"ty": "TYPORA",
"VSCODE": "vsc",
"VISUAL_STUDIO": "vs",
"PYCHARM": "py",
"CLION": "cl",
"GOLAND": "go",
"INTELLIJ_IDEA": "idea",
"ANDROID_STUDIO": "as",
"CURSOR": "cur",
"SUMATRA": "pdf",
"TRAE": "trae",
"VSCODE_SSH": "vscs",
"TYPORA": "ty"
}
```

Expand All @@ -46,27 +48,36 @@ All configurations can be done in the Settings Panel. Change the configurations

- Configure program paths in the following format:

```plaintext
```ini
APP_DOWNLOAD=C:/path/to/app.exe
APP_STORAGE=C:/path/to/storage/file
```

- Each program needs both DOWNLOAD and STORAGE entries
- Example configuration:

```plaintext
```ini
VSCODE_DOWNLOAD=D:/VSCode/bin/code
VSCODE_STORAGE=C:/Users/YourUsername/AppData/Roaming/Code/User/globalStorage/storage.json

VISUAL_STUDIO_DOWNLOAD=D:/VisualStudio/Common7/IDE/devenv.exe
VISUAL_STUDIO_STORAGE=C:/Users/YourUsername/AppData/Local/Microsoft/VisualStudio/17.0_856acfe5/ApplicationPrivateSettings.xml

ANDROID_STUDIO_DOWNLOAD=D:/Android Studio/bin/studio64.exe
ANDROID_STUDIO_STORAGE=C:/Users/YourUsername/AppData/Roaming/Google/AndroidStudio2024.1/options/recentProjects.xml

INTELLIJ_IDEA_DOWNLOAD=D:/IntelliJ IDEA 2024.3/bin/idea64.exe
INTELLIJ_IDEA_STORAGE=C:/Users/YourUsername/AppData/Roaming/JetBrains/IntelliJIdea2024.3/options/recentProjects.xml

GOLAND_DOWNLOAD=D:/goland/GoLand 2023.2/bin/goland64.exe
GOLAND_STORAGE=C:/Users/YourUsername/AppData/Roaming/JetBrains/GoLand2023.2/options/recentProjects.xml

CLION_DOWNLOAD=D:/Clion/CLion 2024.1.4/bin/clion64.exe
CLION_STORAGE=C:/Users/YourUsername/AppData/Roaming/JetBrains/CLion2024.1/options/recentProjects.xml

CURSOR_DOWNLOAD=C:/Users/YourUsername/AppData/Local/Programs/cursor/Cursor.exe
CURSOR_STORAGE=C:/Users/YourUsername/AppData/Roaming/Cursor/globalStorage/storage.json

TYPORA_DOWNLOAD=D:/Typora/Typora.exe
TYPORA_STORAGE=C:/Users/YourUsername/AppData/Roaming/Typora/history.data
```
Expand All @@ -76,7 +87,7 @@ All configurations can be done in the Settings Panel. Change the configurations
- You can customize the program suggestions list displayed when no input is provided.
- Configure program suggestions list in the following format:

```plaintext
```ini
VSCODE
PYCHARM
INTELLIJ_IDEA
Expand All @@ -94,7 +105,7 @@ All configurations can be done in the Settings Panel. Change the configurations

- Configure custom acronyms for your programs in the following format:

```plaintext
```ini
VSCODE=vs
PYCHARM=pc
# ... other acronyms map
Expand Down
Binary file added icons/VISUAL_STUDIO.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion src/application/typora.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ def get_projects(self) -> List[Project]:
all_items.sort(key=lambda x: x["timestamp"], reverse=True)

for item in all_items:
projects.append(Project(self.name, item["path"]))
path = str(item["path"]).replace("\\", "/")
project = Project(self.name, path)
projects.append(project)

return projects
67 changes: 67 additions & 0 deletions src/application/visual_studio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import os
import json
import xml.etree.ElementTree as ET
from typing import List
from ..core.logger import get_logger
from ..core.project import Project
from ..core.registry import ApplicationRegistry
from .base_application import BaseApplication

logger = get_logger()


@ApplicationRegistry.register("VISUAL_STUDIO")
class VisualStudio(BaseApplication):
def __init__(self, download_path: str, storage_file: str):
super().__init__(download_path, storage_file)
self.name = "VISUAL_STUDIO"
self.acronyms = "vs"

def get_projects(self) -> List[Project]:
"""获取Visual Studio最近打开项目路径"""
storage_file = self.storage_file
if storage_file is None or not os.path.exists(storage_file):
raise FileNotFoundError("storage_file not found")
try:
tree = ET.parse(storage_file)
root = tree.getroot()
collection = next(
(
col
for col in root.findall(".//collection")
if col.attrib.get("name") == "CodeContainers.Offline"
),
None,
)
if collection is None:
return []
value_node = next(
(
val
for val in collection.findall("value")
if val.attrib.get("name") == "value"
),
None,
)
value_text = None
if value_node is not None:
value_text = value_node.text or (
value_node.find("data").text
if (value_node.find("data") is not None)
else None
)
if not value_text:
return []
projects_data = json.loads(value_text)
except Exception:
# logger.error(f"解析 Visual Studio 项目 JSON 失败: {e}")
return []
projects = []
for proj in projects_data:
path = proj.get("Value", {}).get("LocalProperties", {}).get("FullPath", "")
if not path:
continue
path = path.replace("\\", "/")
project = Project(self.name, path)
projects.append(project)
return projects
115 changes: 61 additions & 54 deletions src/core/main.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import re
import subprocess
import webbrowser
from typing import Dict, List
Expand Down Expand Up @@ -71,64 +72,62 @@ def query(self, param: str) -> List[Dict[str, str]]:

def context_menu(self, data: str) -> list:
"""
使用任务管理器打开文件夹
复制文件夹路径
使用任务管理器打开文件夹或选中文件
复制文件夹或文件路径
"""
if data is None:
return MessageDTO.asDebugFlowMessage("data is None")
import re

# 正则表达式
pattern = r"^[A-Za-z]:/[\w\-/]+$"

if len(data) > 1 and re.match(pattern, data[1]):
return [
{
"title": "Copy path",
"subTitle": "Press enter to copy the path",
"icoPath": "icons/app.png", # related path to the image
"jsonRPCAction": {
"method": "copy_to_clipboard",
"parameters": [data[1]],
},
"score": 0,
},
{
"title": "Open in explorer",
"subTitle": "Press enter to open the explorer",
"icoPath": "icons/app.png", # related path to the image
"jsonRPCAction": {
"method": "cmd_command",
"parameters": ["start", data[1]],
},
"score": 0,

folder_pattern = r"^[A-Za-z]:/(?:[^/]+/)*[^/]+$"
file_pattern = r"^[A-Za-z]:/(?:[^/]+/)*[^/]+\.[^/]+$"

def copy_path_item(path, type):
return {
"title": f"Copy {type} path",
"subTitle": f"Press enter to copy the {type} path",
"icoPath": "icons/app.png",
"jsonRPCAction": {
"method": "copy_to_clipboard",
"parameters": [path],
},
{
"title": "RecentProjectsOpen's Context menu",
"subTitle": "Press enter to open Flow the plugin's repo in GitHub",
"icoPath": "icons/app.png",
"jsonRPCAction": {
"method": "open_url",
"parameters": [
"https://github.com/Attack825/RecentProjectsOpen"
],
"score": 0,
}

if data is not None and len(data) > 1:
# normalize the path to use forward slashes
path = data[1].replace("\\", "/")
# file path
if re.match(file_pattern, path):
path = path.replace("/", "\\")
logger.debug(f"/e,/select,{path}")
return [
copy_path_item(path, "file"),
{
"title": "Show in explorer",
"subTitle": "Press enter to show and select the file in explorer",
"icoPath": "icons/app.png",
"jsonRPCAction": {
"method": "show_in_explorer",
"parameters": [path],
},
"score": 0,
},
},
]
else:
return MessageDTO.asWarnFlowMessage(
{
"title": "RecentProjectsOpen's Context menu",
"subTitle": "Press enter to open Flow the plugin's repo in GitHub",
"icoPath": "icons/app.png",
"jsonRPCAction": {
"method": "open_url",
"parameters": [
"https://github.com/Attack825/RecentProjectsOpen"
],
]
# folder path
elif re.match(folder_pattern, path):
return [
copy_path_item(path, "folder"),
{
"title": "Open in explorer",
"subTitle": "Press enter to open the folder in explorer",
"icoPath": "icons/app.png",
"jsonRPCAction": {
"method": "cmd_command",
"parameters": ["start", path],
},
"score": 0,
},
},
)
]

return None

def open_url(self, url):
webbrowser.open(url)
Expand All @@ -144,6 +143,14 @@ def cmd_command(self, *args):
shell=True,
)

def show_in_explorer(self, path: str):
_ = subprocess.Popen(
f"explorer /e,/select,{path}",
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True,
)

def copy_to_clipboard(self, text: str):
_ = subprocess.Popen(
["echo", text, "|", "clip"],
Expand Down
Loading