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

REPL Smart Shift+Enter and Dynamic Smart Cursor #21779

Merged
merged 82 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
0577c92
receive file content from ts, parse, collect in py
anthonykim1 Aug 7, 2023
73a38c6
collect top level and comment out potential cursor
anthonykim1 Aug 10, 2023
02a15e6
handle both highlight and non highlight
anthonykim1 Aug 14, 2023
3d91423
remove trailing newline and add test cases
anthonykim1 Aug 16, 2023
f594c85
delete trailing new line and start testing
anthonykim1 Aug 16, 2023
0cacc35
delete trailing new line and add new tests
anthonykim1 Aug 16, 2023
fbe3d5c
fix tests and add printf string test
anthonykim1 Aug 16, 2023
3401e70
add simple list comprehension test
anthonykim1 Aug 17, 2023
ca16633
cherry pick exact statements and pickup inside def
anthonykim1 Aug 17, 2023
7b2769e
fix multiple statements in same line
anthonykim1 Aug 17, 2023
6b20b3c
dynamic cursor movement
anthonykim1 Aug 18, 2023
74eb85a
fix broken prev normalization
anthonykim1 Aug 20, 2023
8cfe2d5
start setting up experiment for smart send
anthonykim1 Aug 21, 2023
6dd2440
make dynamic cursor movement to move to EOL
anthonykim1 Aug 22, 2023
262ac48
fix broken helper.test.ts
anthonykim1 Aug 22, 2023
f63fcc4
fix linting complaints
anthonykim1 Aug 22, 2023
0caad7f
run prettier on help.ts
anthonykim1 Aug 22, 2023
54dc0c7
figure out which line is causing prev test to fail
anthonykim1 Aug 23, 2023
a65d329
investigate previous normalization
anthonykim1 Aug 23, 2023
461851f
uncomment emptyHighlight
anthonykim1 Aug 29, 2023
8f23da7
start setting up experiment for smart send
anthonykim1 Aug 21, 2023
c57fc7d
remove duplicate import in helper.ts
anthonykim1 Sep 12, 2023
5eca7ff
remove duplicate function
anthonykim1 Sep 12, 2023
92cf2fd
format normalize and test_smart_selection
anthonykim1 Sep 12, 2023
143ed5a
format python files for ruff compliance
anthonykim1 Sep 13, 2023
874cb06
add file scope to EventName.EXECUTION_CODE
anthonykim1 Sep 14, 2023
75a2135
add imports for new telemetry scope
anthonykim1 Sep 14, 2023
33b3f5a
fix broken unittest
anthonykim1 Sep 14, 2023
fe0603a
check if node.body is iterable
anthonykim1 Sep 14, 2023
bcf67cb
switch behavior if smart send experiment enabled
anthonykim1 Sep 14, 2023
871e91b
format normalizeSelection
anthonykim1 Sep 14, 2023
360069f
wrapper for undefined values
anthonykim1 Sep 16, 2023
ecb9331
fix linting error
anthonykim1 Sep 18, 2023
9f65f84
clean up normalizeSelection.py
anthonykim1 Sep 18, 2023
930c991
add more test to smart and normalize selection
anthonykim1 Sep 18, 2023
b061479
make black formatter happy
anthonykim1 Sep 18, 2023
20637f7
remove redundant comments
anthonykim1 Sep 19, 2023
13ebe55
bring back configSettings
anthonykim1 Sep 19, 2023
43631cb
clean up helper.ts
anthonykim1 Sep 19, 2023
aacd6ab
disable error for unused configSettings
anthonykim1 Sep 19, 2023
544ac88
add doc string, more comments, eslint for config
anthonykim1 Sep 19, 2023
b0da736
cleaner way to check ast types and node.body
anthonykim1 Sep 19, 2023
4ae8177
format ast_types_with_nodebody
anthonykim1 Sep 19, 2023
ee40d5f
utilize f string as recommended
anthonykim1 Sep 19, 2023
d71352c
simplify empty_highlight assignment and format
anthonykim1 Sep 19, 2023
d7997ed
fix test_normalize_selection
anthonykim1 Sep 19, 2023
2fda1ce
more docstring
anthonykim1 Sep 19, 2023
7db00f4
simplify activeEditor conditional
anthonykim1 Sep 19, 2023
a9bd9a1
better ts syntax for start,endline and highlight
anthonykim1 Sep 19, 2023
039c1de
cleaner contents.get
anthonykim1 Sep 19, 2023
96a5f30
more tests added in test_smart_selection
anthonykim1 Sep 19, 2023
9428578
fix test_part_dictionary test
anthonykim1 Sep 19, 2023
afe9a72
format, more comments
anthonykim1 Sep 19, 2023
6768f85
new function moveToNextBlock
anthonykim1 Sep 19, 2023
194e413
comment before the function for moveToNextBlock
anthonykim1 Sep 19, 2023
4c6a0ba
prevent access .getText from undefined
anthonykim1 Sep 19, 2023
3b11ed8
remove should_run_top_blocks from global variable
anthonykim1 Sep 20, 2023
094a5de
delete global_next_lineno
anthonykim1 Sep 20, 2023
c8b0e8c
comply to new return value for traverse_file
anthonykim1 Sep 20, 2023
8d640aa
fix linting error unbound variable
anthonykim1 Sep 20, 2023
dc9a6de
fix linting error attempt2
anthonykim1 Sep 20, 2023
bd4abf2
set default which_line_next value
anthonykim1 Sep 20, 2023
9987441
format with black
anthonykim1 Sep 20, 2023
23a1c16
add test_dynamic_cursor
anthonykim1 Sep 20, 2023
97f9e2b
more tests
anthonykim1 Sep 20, 2023
6ff726d
more tests smart_selection, dynamic_cursor
anthonykim1 Sep 20, 2023
482c4ab
more test cases
anthonykim1 Sep 20, 2023
5c03e54
moveToNextBlock as private
anthonykim1 Sep 21, 2023
4d21121
typescript testing for cursor move
anthonykim1 Sep 25, 2023
94146cf
smart selection typescript
anthonykim1 Sep 26, 2023
ccaaef5
more typescript tests
anthonykim1 Oct 2, 2023
848b80d
save more tests
anthonykim1 Oct 2, 2023
3643651
add more tests
anthonykim1 Oct 3, 2023
15ad56b
add smoke test for smart send
anthonykim1 Oct 8, 2023
905a31d
delete unnecessary comment
anthonykim1 Oct 9, 2023
36f5d5b
move moveCursor to private
anthonykim1 Oct 9, 2023
b70b0f1
comment out smoke test
anthonykim1 Oct 9, 2023
4f4c86a
clean up variable names
anthonykim1 Oct 9, 2023
9450f76
format and rename variables
anthonykim1 Oct 9, 2023
d416fec
leave out smoke test for now
anthonykim1 Oct 9, 2023
004dab2
format normalizeSelection
anthonykim1 Oct 9, 2023
99ee2ce
Update src/client/terminals/codeExecution/helper.ts
anthonykim1 Oct 10, 2023
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
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -544,14 +544,16 @@
"pythonSurveyNotification",
"pythonPromptNewToolsExt",
"pythonTerminalEnvVarActivation",
"pythonTestAdapter"
"pythonTestAdapter",
"pythonREPLSmartSend"
],
"enumDescriptions": [
"%python.experiments.All.description%",
"%python.experiments.pythonSurveyNotification.description%",
"%python.experiments.pythonPromptNewToolsExt.description%",
"%python.experiments.pythonTerminalEnvVarActivation.description%",
"%python.experiments.pythonTestAdapter.description%"
"%python.experiments.pythonTestAdapter.description%",
"%python.experiments.pythonREPLSmartSend.description%"
]
},
"scope": "machine",
Expand All @@ -567,14 +569,16 @@
"pythonSurveyNotification",
"pythonPromptNewToolsExt",
"pythonTerminalEnvVarActivation",
"pythonTestAdapter"
"pythonTestAdapter",
"pythonREPLSmartSend"
],
"enumDescriptions": [
"%python.experiments.All.description%",
"%python.experiments.pythonSurveyNotification.description%",
"%python.experiments.pythonPromptNewToolsExt.description%",
"%python.experiments.pythonTerminalEnvVarActivation.description%",
"%python.experiments.pythonTestAdapter.description%"
"%python.experiments.pythonTestAdapter.description%",
"%python.experiments.pythonREPLSmartSend.description%"
]
},
"scope": "machine",
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"python.experiments.pythonPromptNewToolsExt.description": "Denotes the Python Prompt New Tools Extension experiment.",
"python.experiments.pythonTerminalEnvVarActivation.description": "Enables use of environment variables to activate terminals instead of sending activation commands.",
"python.experiments.pythonTestAdapter.description": "Denotes the Python Test Adapter experiment.",
"python.experiments.pythonREPLSmartSend.description": "Denotes the Python REPL Smart Send experiment.",
"python.formatting.autopep8Args.description": "Arguments passed in. Each argument is a separate item in the array.",
"python.formatting.autopep8Args.markdownDeprecationMessage": "This setting will soon be deprecated. Please use the [Autopep8 extension](https://marketplace.visualstudio.com/items?itemName=ms-python.autopep8). <br>Learn more [here](https://aka.ms/AAlgvkb).",
"python.formatting.autopep8Args.deprecationMessage": "This setting will soon be deprecated. Please use the Autopep8 extension. Learn more here: https://aka.ms/AAlgvkb.",
Expand Down
149 changes: 147 additions & 2 deletions pythonFiles/normalizeSelection.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import re
import sys
import textwrap
from typing import Iterable


def split_lines(source):
Expand Down Expand Up @@ -118,6 +119,8 @@ def normalize_lines(selection):

# Insert a newline between each top-level statement, and append a newline to the selection.
source = "\n".join(statements) + "\n"
if selection[-2] == "}":
source = source[:-1]
except Exception:
# If there's a problem when parsing statements,
# append a blank line to end the block and send it as-is.
Expand All @@ -126,17 +129,159 @@ def normalize_lines(selection):
return source


top_level_nodes = []
min_key = None


def check_exact_exist(top_level_nodes, start_line, end_line):
exact_nodes = []
for node in top_level_nodes:
if node.lineno == start_line and node.end_lineno == end_line:
exact_nodes.append(node)

return exact_nodes


def traverse_file(wholeFileContent, start_line, end_line, was_highlighted):
anthonykim1 marked this conversation as resolved.
Show resolved Hide resolved
"""
Intended to traverse through a user's given file content and find, collect all appropriate lines
that should be sent to the REPL in case of smart selection.
This could be exact statement such as just a single line print statement,
or a multiline dictionary, or differently styled multi-line list comprehension, etc.
Then call the normalize_lines function to normalize our smartly selected code block.
"""

parsed_file_content = ast.parse(wholeFileContent)
smart_code = ""
should_run_top_blocks = []

# Purpose of this loop is to fetch and collect all the
# AST top level nodes, and its node.body as child nodes.
# Individual nodes will contain information like
# the start line, end line and get source segment information
# that will be used to smartly select, and send normalized code.
for node in ast.iter_child_nodes(parsed_file_content):
top_level_nodes.append(node)

ast_types_with_nodebody = (
ast.Module,
ast.Interactive,
ast.Expression,
ast.FunctionDef,
ast.AsyncFunctionDef,
ast.ClassDef,
ast.For,
ast.AsyncFor,
ast.While,
ast.If,
ast.With,
ast.AsyncWith,
ast.Try,
ast.Lambda,
ast.IfExp,
ast.ExceptHandler,
)
if isinstance(node, ast_types_with_nodebody) and isinstance(
node.body, Iterable
):
for child_nodes in node.body:
top_level_nodes.append(child_nodes)

exact_nodes = check_exact_exist(top_level_nodes, start_line, end_line)

# Just return the exact top level line, if present.
if len(exact_nodes) > 0:
which_line_next = 0
for same_line_node in exact_nodes:
should_run_top_blocks.append(same_line_node)
smart_code += (
f"{ast.get_source_segment(wholeFileContent, same_line_node)}\n"
)
which_line_next = get_next_block_lineno(should_run_top_blocks)
return {
"normalized_smart_result": smart_code,
"which_line_next": which_line_next,
}

# For each of the nodes in the parsed file content,
# add the appropriate source code line(s) to be sent to the REPL, dependent on
# user is trying to send and execute single line/statement or multiple with smart selection.
for top_node in ast.iter_child_nodes(parsed_file_content):
if start_line == top_node.lineno and end_line == top_node.end_lineno:
should_run_top_blocks.append(top_node)

smart_code += f"{ast.get_source_segment(wholeFileContent, top_node)}\n"
break # If we found exact match, don't waste computation in parsing extra nodes.
elif start_line >= top_node.lineno and end_line <= top_node.end_lineno:
# Case to apply smart selection for multiple line.
# This is the case for when we have to add multiple lines that should be included in the smart send.
# For example:
# 'my_dictionary': {
# 'Audi': 'Germany',
# 'BMW': 'Germany',
# 'Genesis': 'Korea',
# }
# with the mouse cursor at 'BMW': 'Germany', should send all of the lines that pertains to my_dictionary.

should_run_top_blocks.append(top_node)

smart_code += str(ast.get_source_segment(wholeFileContent, top_node))
smart_code += "\n"

normalized_smart_result = normalize_lines(smart_code)
which_line_next = get_next_block_lineno(should_run_top_blocks)
return {
"normalized_smart_result": normalized_smart_result,
"which_line_next": which_line_next,
}


# Look at the last top block added, find lineno for the next upcoming block,
# This will be used in calculating lineOffset to move cursor in VS Code.
def get_next_block_lineno(which_line_next):
last_ran_lineno = int(which_line_next[-1].end_lineno)
next_lineno = int(which_line_next[-1].end_lineno)

for reverse_node in top_level_nodes:
if reverse_node.lineno > last_ran_lineno:
next_lineno = reverse_node.lineno
break
return next_lineno


if __name__ == "__main__":
# Content is being sent from the extension as a JSON object.
# Decode the data from the raw bytes.
stdin = sys.stdin if sys.version_info < (3,) else sys.stdin.buffer
raw = stdin.read()
contents = json.loads(raw.decode("utf-8"))
# Empty highlight means user has not explicitly selected specific text.
empty_Highlight = contents.get("emptyHighlight", False)

normalized = normalize_lines(contents["code"])
# We also get the activeEditor selection start line and end line from the typescript VS Code side.
# Remember to add 1 to each of the received since vscode starts line counting from 0 .
vscode_start_line = contents["startLine"] + 1
vscode_end_line = contents["endLine"] + 1

# Send the normalized code back to the extension in a JSON object.
data = json.dumps({"normalized": normalized})
data = None
which_line_next = 0

if empty_Highlight and contents.get("smartSendExperimentEnabled"):
result = traverse_file(
contents["wholeFileContent"],
vscode_start_line,
vscode_end_line,
not empty_Highlight,
)
normalized = result["normalized_smart_result"]
which_line_next = result["which_line_next"]
data = json.dumps(
{"normalized": normalized, "nextBlockLineno": result["which_line_next"]}
)
else:
normalized = normalize_lines(contents["code"])
data = json.dumps({"normalized": normalized})

stdout = sys.stdout if sys.version_info < (3,) else sys.stdout.buffer
stdout.write(data.encode("utf-8"))
Expand Down
Loading
Loading