Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generalize file-based RPC command client beyond VSCode #956

Merged
merged 47 commits into from
Sep 10, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
423a261
split command client to applicactions
Aug 13, 2022
df2e523
Remove trailing white space
Aug 13, 2022
a345741
More white space
Aug 13, 2022
9304e22
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 13, 2022
09ef97e
Address CR comments
Aug 19, 2022
613281d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 19, 2022
2f5c726
Remove error producing pre-phrase-signal
Aug 20, 2022
dbb6893
Make VSCode Shim
Aug 21, 2022
211802a
Add Shim
Aug 21, 2022
a7c1c52
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 21, 2022
01bc65d
Remove unneeded function from tag
Aug 22, 2022
8d57e34
Merge branch 'feature/command-client-re-use' of https://github.com/Jo…
Aug 22, 2022
ce14610
Add comment to vscode
Aug 22, 2022
4c9c482
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 22, 2022
27aa1f3
fix up some types & docs
rntz Aug 24, 2022
640af19
implement emit_pre_phrase_signal on module instead of in global context
rntz Aug 24, 2022
c2fbf32
typo
rntz Aug 24, 2022
295f843
restore some lines, remove unnecessary print
rntz Aug 24, 2022
c41f842
remove unwanted changes
rntz Aug 24, 2022
7717e82
Remove duplicated code
Aug 25, 2022
340b707
Remove run_command and rename
Aug 25, 2022
2d83c9d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 25, 2022
4badb6c
Remove string from mong language
Aug 28, 2022
eb5254b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 28, 2022
00343b4
Remove string import left
Aug 28, 2022
34ae8e9
double check missing newlines
Sep 1, 2022
9fdac7e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 1, 2022
8cb4444
Remove string
Sep 1, 2022
0522403
Remove string
Sep 1, 2022
0f87908
Merge branch 'feature/command-client-re-use' of https://github.com/Jo…
Sep 1, 2022
40d8ee0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 1, 2022
4d7609f
Alter missing directory error msg
Sep 1, 2022
054e81f
Rename time out
Sep 1, 2022
c5eb3ab
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 1, 2022
a8a1409
Remove client from comment
Sep 4, 2022
5b0d283
Moved comment
Sep 4, 2022
347c9b3
Removed 'final' from comment
Sep 4, 2022
571abce
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 4, 2022
b9719f5
remove comment pre phrase from tag
Sep 4, 2022
13e7d70
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 4, 2022
39478d5
Merge branch 'feature/command-client-re-use' of https://github.com/Jo…
Sep 4, 2022
f831999
command server => rpc
Sep 4, 2022
033eae5
Merge branch 'feature/command-client-re-use' of https://github.com/Jo…
Sep 4, 2022
29afd9a
fix emit_pre_phrase_signal
rntz Sep 4, 2022
173ebef
fix "tag: command_client"
rntz Sep 4, 2022
d7e89b1
Fixes
pokey Sep 6, 2022
3d1e016
Update apps/vscode/command_client/visual_studio.py
rntz Sep 6, 2022
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
52 changes: 22 additions & 30 deletions apps/vscode/command_client/command_client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import os
import string
rntz marked this conversation as resolved.
Show resolved Hide resolved
import time
from dataclasses import dataclass
from pathlib import Path
Expand All @@ -13,10 +14,10 @@
# to remove it
STALE_TIMEOUT_MS = 60_000

# The amount of time to wait for VSCode to perform a command, in seconds
# The amount of time to wait for client application to perform a command, in seconds
rntz marked this conversation as resolved.
Show resolved Hide resolved
VSCODE_COMMAND_TIMEOUT_SECONDS = 3.0
rntz marked this conversation as resolved.
Show resolved Hide resolved

# When doing exponential back off waiting for vscode to perform a command, how
# When doing exponential back off waiting for client application to perform a command, how
# long to sleep the first time
MINIMUM_SLEEP_TIME_SECONDS = 0.0005

Expand All @@ -32,7 +33,7 @@
linux_ctx = Context()

ctx.matches = r"""
app: vscode
tag: command_client
rntz marked this conversation as resolved.
Show resolved Hide resolved
"""
mac_ctx.matches = r"""
os: mac
Expand All @@ -49,13 +50,6 @@ def __repr__(self):
return "<argument not set>"


def run_vscode_command_by_command_palette(command_id: str):
"""Execute command via command palette. Preserves the clipboard."""
actions.user.command_palette()
actions.user.paste(command_id)
actions.key("enter")


def write_json_exclusive(path: Path, body: Any):
"""Writes jsonified object to file, failing if the file already exists

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one more 😅

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Expand Down Expand Up @@ -88,11 +82,9 @@ def to_dict(self):
def write_request(request: Request, path: Path):
"""Converts the given request to json and writes it to the file, failing if
the file already exists unless it is stale in which case it replaces it

Args:
request (Request): The request to serialize
path (Path): The path to write to

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't look fixed? still deleting lines here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double checked should be fixed.

Raises:
Exception: If another process has an active request file
"""
Expand Down Expand Up @@ -123,14 +115,13 @@ def handle_existing_request_file(path):
robust_unlink(path)


def run_vscode_command(
def run_command(
command_id: str,
*args: str,
wait_for_finish: bool = False,
return_command_output: bool = False,
):
"""Runs a VSCode command, using command server if available

"""Runs a command, using command server if available
Args:
command_id (str): The ID of the VSCode command to run
wait_for_finish (bool, optional): Whether to wait for the command to finish before returning. Defaults to False.
Expand All @@ -153,7 +144,7 @@ def run_vscode_command(
if args or return_command_output:
raise Exception("Must use command-server extension for advanced commands")
print("Communication dir not found; falling back to command palette")
run_vscode_command_by_command_palette(command_id)
actions.user.command_client_fallback(command_id)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea would be to throw an exception here

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return

request_path = communication_dir_path / "request.json"
Expand All @@ -180,9 +171,9 @@ def run_vscode_command(
print("WARNING: Found old response file")
robust_unlink(response_path)

# Then, perform keystroke telling VSCode to execute the command in the
# request file. Because only the active VSCode instance will accept
# keypresses, we can be sure that the active VSCode instance will be the
# Then, perform keystroke telling client application to execute the command in the
# request file. Because only the active client application instance will accept
# keypresses, we can be sure that the active client application instance will be the
# one to execute the command.
actions.user.trigger_command_server_command_execution()

Expand Down Expand Up @@ -221,7 +212,7 @@ def get_communication_dir_path():
if hasattr(os, "getuid"):
suffix = f"-{os.getuid()}"

return Path(gettempdir()) / f"vscode-command-server{suffix}"
return Path(gettempdir()) / f"{actions.user.command_server_directory()}{suffix}"


def robust_unlink(path: Path):
Expand Down Expand Up @@ -292,14 +283,14 @@ class Actions:
def vscode(command_id: str):
"""Execute command via vscode command server, if available, or fallback
to command palette."""
run_vscode_command(command_id)
run_command(command_id)

def vscode_and_wait(command_id: str):
"""Execute command via vscode command server, if available, and wait
for command to finish. If command server not available, uses command
palette and doesn't guarantee that it will wait for command to
finish."""
run_vscode_command(command_id, wait_for_finish=True)
run_command(command_id, wait_for_finish=True)

def vscode_with_plugin(
command_id: str,
Expand All @@ -310,7 +301,7 @@ def vscode_with_plugin(
arg5: Any = NotSet,
):
"""Execute command via vscode command server."""
run_vscode_command(
run_command(
command_id,
arg1,
arg2,
Expand All @@ -328,7 +319,7 @@ def vscode_with_plugin_and_wait(
arg5: Any = NotSet,
):
"""Execute command via vscode command server and wait for command to finish."""
run_vscode_command(
run_command(
command_id,
arg1,
arg2,
Expand All @@ -347,7 +338,7 @@ def vscode_get(
arg5: Any = NotSet,
) -> Any:
"""Execute command via vscode command server and return command output."""
return run_vscode_command(
return run_command(
command_id,
arg1,
arg2,
Expand All @@ -357,18 +348,21 @@ def vscode_get(
return_command_output=True,
)

def command_server_directory() -> string:
rntz marked this conversation as resolved.
Show resolved Hide resolved
"""Return the final directory of the command server"""
rntz marked this conversation as resolved.
Show resolved Hide resolved

def trigger_command_server_command_execution():
"""Issue keystroke to trigger command server to execute command that
was written to the file. For internal use only"""
actions.key("ctrl-shift-f17")

def emit_pre_phrase_signal() -> bool:
"""Touches a file to indicate that a phrase is about to begin execution"""

def did_emit_pre_phrase_signal() -> bool:
"""Indicates whether the pre-phrase signal was emitted at the start of this phrase"""
return did_emit_pre_phrase_signal

def command_client_fallback(command_id: str):
"""The strategy to use when no command server directory is located for the the application"""


@mac_ctx.action_class("user")
class MacUserActions:
Expand Down Expand Up @@ -406,10 +400,8 @@ class MissingCommunicationDir(Exception):
def get_signal_path(name: str) -> Path:
"""
Get the path to a signal in the signal subdirectory.

Args:
name (str): The name of the signal

Returns:
Path: The signal path
"""
Expand Down
24 changes: 24 additions & 0 deletions apps/vscode/command_client/command_client_tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import string
rntz marked this conversation as resolved.
Show resolved Hide resolved

from talon import Module

mod = Module()

mod.tag(
"command_client", desc="For applications which implement File based RPC with Talon"
)


@mod.action_class
class Actions:
def command_server_directory() -> string:
"""The dirctory which contains the files required for communication between the application and Talon.
This is the only function which absolutly must be implemented for any application using the command-client."""

def emit_pre_phrase_signal() -> bool:
"""The command client can touch a signal file at the start of a phrase, function has a default implementation
which does this, if your implementation does not require this signal file be touched simply return false."""

def command_client_fallback(command_id: str):
"""Execute an alternative stratagy for issuing the command, if non exists just implemnt
there is not need to implement, the fall back is to do nothing."""
17 changes: 17 additions & 0 deletions apps/vscode/command_client/visual_studio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import string
rntz marked this conversation as resolved.
Show resolved Hide resolved

from talon import Context, actions

ctx = Context()

ctx.matches = r"""
app: visual_studio
"""

ctx.tags = ["user.command_client"]


@ctx.action_class("user")
class VisualStudioActions:
def command_server_directory() -> string:
return "visual-studio-commandServer"
rntz marked this conversation as resolved.
Show resolved Hide resolved
22 changes: 22 additions & 0 deletions apps/vscode/command_client/vs_code.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import string
rntz marked this conversation as resolved.
Show resolved Hide resolved

from talon import Context, actions

ctx = Context()

ctx.matches = r"""
app: vscode
"""
ctx.tags = ["user.command_client"]


@ctx.action_class("user")
class VsCodeAction:
def command_server_directory() -> string:
return "vscode-command-server"

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then define the action vscode here, and call the run_command action, wrapped in a try-catch. If it throws an error, do the fallback

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, this but duplicated code

def command_client_fallback(command_id: str):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then you can remove this action; just inline into vscode above

"""Execute command via command palette. Preserves the clipboard."""
actions.user.command_palette()
actions.user.paste(command_id)
actions.key("enter")