dotfiles/talon/community/community-cursorless-0.4.0/apps/jetbrains/jetbrains.py
2024-11-16 20:27:38 -07:00

206 lines
6.1 KiB
Python

import os
import os.path
import requests
import time
from pathlib import Path
from talon import ctrl, ui, Module, Context, actions, clip
import tempfile
# Courtesy of https://github.com/anonfunc/talon-user/blob/master/apps/jetbrains.py
extendCommands = []
# Each IDE gets its own port, as otherwise you wouldn't be able
# to run two at the same time and switch between them.
# Note that MPS and IntelliJ ultimate will conflict...
port_mapping = {
"com.google.android.studio": 8652,
"com.jetbrains.AppCode": 8655,
"com.jetbrains.CLion": 8657,
"com.jetbrains.datagrip": 8664,
"com.jetbrains.goland-EAP": 8659,
"com.jetbrains.goland": 8659,
"com.jetbrains.intellij-EAP": 8653,
"com.jetbrains.intellij.ce": 8654,
"com.jetbrains.intellij": 8653,
"com.jetbrains.PhpStorm": 8662,
"com.jetbrains.pycharm": 8658,
"com.jetbrains.rider": 8660,
"com.jetbrains.rubymine": 8661,
"com.jetbrains.rubymine-EAP": 8661,
"com.jetbrains.WebStorm": 8663,
"google-android-studio": 8652,
"idea64.exe": 8653,
"IntelliJ IDEA": 8653,
"jetbrains-appcode": 8655,
"jetbrains-clion": 8657,
"jetbrains-datagrip": 8664,
"jetbrains-goland-eap": 8659,
"jetbrains-goland": 8659,
"jetbrains-idea-ce": 8654,
"jetbrains-idea-eap": 8653,
"jetbrains-idea": 8653,
"jetbrains-phpstorm": 8662,
"jetbrains-pycharm-ce": 8658,
"jetbrains-pycharm": 8658,
"jetbrains-rider": 8660,
"jetbrains-rubymine": 8661,
"jetbrains-rubymine-eap": 8661,
"jetbrains-studio": 8652,
"jetbrains-webstorm": 8663,
"RubyMine": 8661,
"RubyMine-EAP": 8661,
"PyCharm": 8658,
"pycharm64.exe": 8658,
"webstorm64.exe": 8663,
}
def _get_nonce(port, file_prefix):
file_name = file_prefix + str(port)
try:
with open(os.path.join(tempfile.gettempdir(), file_name), "r") as fh:
return fh.read()
except FileNotFoundError as e:
try:
home = str(Path.home())
with open(os.path.join(home, file_name), "r") as fh:
return fh.read()
except FileNotFoundError as eb:
print(f"Could not find {file_name} in tmp or home")
return None
except IOError as e:
print(e)
return None
def send_idea_command(cmd):
print("Sending {}".format(cmd))
active_app = ui.active_app()
bundle = active_app.bundle or active_app.name
port = port_mapping.get(bundle, None)
nonce = _get_nonce(port, ".vcidea_") or _get_nonce(port, "vcidea_")
print(f"sending {bundle} {port} {nonce}")
if port and nonce:
response = requests.get(
"http://localhost:{}/{}/{}".format(port, nonce, cmd), timeout=(0.05, 3.05)
)
response.raise_for_status()
return response.text
def get_idea_location():
return send_idea_command("location").split()
def idea_commands(commands):
command_list = commands.split(",")
print("executing jetbrains", commands)
global extendCommands
extendCommands = command_list
for cmd in command_list:
if cmd:
send_idea_command(cmd.strip())
time.sleep(0.1)
ctx = Context()
mod = Module()
mod.apps.jetbrains = "app.name: /jetbrains/"
mod.apps.jetbrains = "app.name: IntelliJ IDEA"
mod.apps.jetbrains = "app.name: PyCharm"
mod.apps.jetbrains = "app.name: RubyMine"
mod.apps.jetbrains = "app.name: RubyMine-EAP"
# windows
mod.apps.jetbrains = "app.name: idea64.exe"
mod.apps.jetbrains = "app.name: PyCharm64.exe"
mod.apps.jetbrains = "app.name: pycharm64.exe"
mod.apps.jetbrains = "app.name: webstorm64.exe"
mod.apps.jetbrains = """
os: mac
and app.bundle: com.jetbrains.pycharm
"""
@mod.action_class
class Actions:
def idea(commands: str):
"""Send a command to Jetbrains product"""
idea_commands(commands)
def idea_grab(times: int):
"""Copies specified number of words to the left"""
old_clip = clip.get()
try:
original_line, original_column = get_idea_location()
for _ in range(times):
send_idea_command("action EditorSelectWord")
send_idea_command("action EditorCopy")
send_idea_command("goto {} {}".format(original_line, original_column))
send_idea_command("action EditorPaste")
finally:
clip.set(old_clip)
global extendCommands
extendCommands = []
ctx.matches = r"""
app: jetbrains
"""
@ctx.action_class("win")
class win_actions:
def filename():
title = actions.win.title()
result = title.split(" ")
for word in result:
if "." in word:
return word
return ""
@ctx.action_class("edit")
class edit_actions:
def jump_line(n: int):
actions.user.idea("goto {} 0".format(n))
# move the cursor to the first nonwhite space character of the line
actions.user.idea("action EditorLineEnd")
actions.user.idea("action EditorLineStart")
@ctx.action_class("user")
class user_actions:
def tab_jump(number: int):
# depends on plugin GoToTabs
if number < 10:
actions.user.idea("action GoToTab{}".format(number))
def extend_until_line(line: int):
actions.user.idea("extend {}".format(line))
def select_range(line_start: int, line_end: int):
# if it's a single line, select the entire thing including the ending new-line5
if line_start == line_end:
actions.user.idea("goto {} 0".format(line_start))
actions.user.idea("action EditorSelectLine"),
else:
actions.user.idea("range {} {}".format(line_start, line_end))
def extend_camel_left():
actions.user.idea("action EditorPreviousWordInDifferentHumpsModeWithSelection")
def extend_camel_right():
actions.user.idea("action EditorNextWordInDifferentHumpsModeWithSelection")
def camel_left():
actions.user.idea("action EditorPreviousWordInDifferentHumpsMode")
def camel_right():
actions.user.idea("action EditorNextWordInDifferentHumpsMode")
def line_clone(line: int):
actions.user.idea("clone {}".format(line))