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

Add support for copying code snippets #1455

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

rsashank
Copy link
Member

@rsashank rsashank commented Dec 25, 2023

What does this PR do, and why?

Introduces the ability to copy code snippets, building upon the groundwork laid by @yuktasarode, @kingjuno, and @neiljp in previous pull requests: #1134 #1353.

This PR incorporates feedback from earlier pull requests. It introduces the k keybinding for copying code from a Message Information Popup. This PR also resolves the previous issue of a flashing cursor on the button.

Additionally, it includes a minor refactoring in copy_to_clipboard to address return carriage differences in WSL.

External discussion & connections

How did you test this?

  • Manually - Behavioral changes
  • Manually - Visual changes
  • Adapting existing automated tests
  • Adding automated tests for new behavior (or missing tests)
  • Existing automated tests should already cover this (only a refactor of tested code)

Self-review checklist for each commit

  • It is a minimal coherent idea
  • It has a commit summary following the documented style (title & body)
  • It has a commit summary describing the motivation and reasoning for the change
  • It individually passes linting and tests
  • It contains test additions for any new behavior
  • It flows clearly from a previous branch commit, and/or prepares for the next commit
CopyCodeSnippet.mp4

@zulipbot zulipbot added size: XL [Automatic label added by zulipbot] good first issue Good for newcomers missing feature: user A missing feature for all users, present in another Zulip client version parity: 4 labels Dec 25, 2023
@rsashank rsashank changed the title Add support for copying code snippets WIP: Add support for copying code snippets Dec 25, 2023
@rsashank rsashank force-pushed the codesnippet1123 branch 3 times, most recently from d7a1b65 to 44b035b Compare December 25, 2023 21:00
@rsashank
Copy link
Member Author

I removed the expected_code_width parameter from the test_create_code_snippet_buttons test. The expected width of code snippets seems to vary across different versions of Ubuntu and MacOS.

Should I reintroduce the test with platform-specific expected code widths, or is it acceptable to leave it removed?

@rsashank rsashank changed the title WIP: Add support for copying code snippets Add support for copying code snippets Dec 25, 2023
@rsashank
Copy link
Member Author

@zulipbot add "PR needs review"

@zulipbot zulipbot added the PR needs review PR requires feedback to proceed label Dec 25, 2023
@rsashank rsashank force-pushed the codesnippet1123 branch 3 times, most recently from 2b8be1f to a012674 Compare December 25, 2023 21:29
@rsashank rsashank force-pushed the codesnippet1123 branch 6 times, most recently from 45201c8 to fee1ed8 Compare February 10, 2024 11:18
@rsashank rsashank force-pushed the codesnippet1123 branch 3 times, most recently from 802ab9c to e7929db Compare April 14, 2024 09:23
zulipterminal/core.py Outdated Show resolved Hide resolved
@rsashank
Copy link
Member Author

Updated this PR :)
@zulipbot add "PR needs review"

@zulipbot
Copy link
Member

ERROR: Label "PR needs review" already exists and was thus not added to this pull request.

Copy link
Collaborator

@neiljp neiljp left a comment

Choose a reason for hiding this comment

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

@rsashank Thanks for taking this forward 👍

I know this was a followup on previous work, so some of my comments aren't necessarily directed at your approach.

That said, some commits likely benefit from co-author labelling, which you've handled previously.

I'm not sure where the 'Code snippet' term came from originally, but I wonder if we would be better served by using Code block instead?

For now we may want to hold off on the last commit since

  • Viewing Actions generally applies to the message itself, not one of the selected buttons
  • We don't have copy for other actions
  • This will be cleaner once we have Sushmey's category headings in place

I'd like us to remember to do some refactoring of the chunks of metadata we're passing around everywhere, that we'll add to here ;) Doing that first would simplify this PR, but would also delay it.

zulipterminal/core.py Outdated Show resolved Hide resolved
zulipterminal/ui_tools/views.py Outdated Show resolved Hide resolved
zulipterminal/ui_tools/messages.py Outdated Show resolved Hide resolved
zulipterminal/ui_tools/buttons.py Show resolved Hide resolved
Comment on lines 714 to 715
def copy_to_clipboard(self, *_: Any) -> None:
self.controller.copy_to_clipboard(self.copy_code, "Code")
Copy link
Collaborator

Choose a reason for hiding this comment

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

It looks like you changed this compared to the previous PR? ("code" -> "Code"?)

I think it would be clearer to change the clipboard method, since it's using the string passed as output.

If a message has multiple code blocks, it may also be useful to indicate which one is copied!

Copy link
Member Author

Choose a reason for hiding this comment

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

I've updated this method to get copy_code only on demand as suggested in another comment. I've also made it indicate which code block has been copied.

Is that fine?

Comment on lines 717 to 719
def get_code_from_snippet(
self, snippet_list: List[Tuple[str, str]]
) -> Tuple[List[Tuple[str, str]], str]:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Following on some other comments, this function may not be necessary in the same way, but:

See my general comment re the naming we've ended up with here, but in regard to this method:

  • This method returns two things, which the method name does not suggest is the case
  • The returned items are described in the comment; fine details are good there, but the name should describe what it does as much as possible :)

Copy link
Member Author

Choose a reason for hiding this comment

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

I've revised this method to focus solely on extracting display_code from snippet_list.

Comment on lines 1732 to 1734
display_code, copy_code = CodeSnippetButton.get_code_from_snippet(
self, snippet_list
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

There doesn't appear to be a change here compared to the previous PR, where I made a comment. I'll add some different notes here since I'm looking at it afresh.

Passing in a self here which is completely different from the other self (a different class & hierarchy) is quite a 'code smell' that something is going oddly. It's working OK since the method doesn't even use self! We're using the function before we initialize a button to have an appropriate self, if we needed one.

The other aspect is that we're using this method to get the raw code (copy_code), and then only passing it into the button initializer - which the button could calculate itself once it has the full 'code snippet' data, and only on demand if it is copied.

Similarly, if the button had the code snippet data, it could provide the display_code, or even just the widths - so this logic could be retained inside the button itself.

Copy link
Member Author

Choose a reason for hiding this comment

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

Got it! That makes sense 👍

I've updated the copy_code to only be extracted from snippet_list on demand. Also updated this function to extract display_code from snippet_list once the Button is initialized.

zulipterminal/ui_tools/messages.py Outdated Show resolved Hide resolved
Comment on lines 756 to 764
(
content,
self.message_links,
self.code_snippets,
self.time_mentions,
) = self.transform_content(self.message["content"], self.model.server_url)
Copy link
Collaborator

Choose a reason for hiding this comment

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

It'd be good to see some tests for what ends up in self.code_snippets, though we don't seem to have tests for the others.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm yet to work on adding these tests and was wondering if it would be alright moving this to a separate PR? I'll also include tests for the others as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a test for self.code_snippets. I'll add tests for the others in a separate PR 👍

Copy link
Member Author

Choose a reason for hiding this comment

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

Made a PR for tests for the others :)

Comment on lines 585 to 588
if code_language != "Text only":
metadata["code_snippets"].append((code_language, code_snippet))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we have an example of this? There are no tests or comments to explain this.

Also, what happens for this when data-code-language is absent?

I've seen cases where it looks like no language tag was applied and the code is not highlighted (what language should we show?)

However, also cases where the code is highlighted, and the source message has a language tag - but the current code also thinks there is no language present. This suggests another field was used previously?

Copy link
Collaborator

Choose a reason for hiding this comment

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

It's possible the language data was not available, or was tagged elsewhere, in a previous version of the Zulip markup. This was hinted at in zulip/zulip#11618.

Copy link
Member Author

@rsashank rsashank May 28, 2024

Choose a reason for hiding this comment

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

When you put text after the 3 backticks (```), it causes the code_language to be "Text only". It seems they intended to avoid including that as a code snippet for some reason.

I'm looking into where the language data was previously tagged.

@neiljp neiljp removed the PR needs review PR requires feedback to proceed label Apr 18, 2024
@zormit zormit requested a review from Niloth-p May 29, 2024 19:54
@rsashank rsashank force-pushed the codesnippet1123 branch 2 times, most recently from a7d74f6 to 7e27991 Compare June 3, 2024 11:23
Copy link
Collaborator

@Niloth-p Niloth-p left a comment

Choose a reason for hiding this comment

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

Great work, Sashank!
Ran it, and it works fine on Linux.

I noticed a few changes suggested by Neil, that are pending.

  • Renaming: 'code blocks' instead of 'code snippets'. Which I noticed you've changed in the footer text, but other occurrences remain.
  • Adding attributions
  • The ambiguity about the languages part

Follow-up PR: metadata refactor

zulipterminal/core.py Outdated Show resolved Hide resolved
tests/ui_tools/test_popups.py Outdated Show resolved Hide resolved
zulipterminal/ui_tools/messages.py Show resolved Hide resolved
zulipterminal/ui_tools/messages.py Outdated Show resolved Hide resolved
len(max(code_snippet_widgets[index].display_code, key=len)),
)

code = caption + str(snip[1] for snip in snippet_list)
Copy link
Collaborator

Choose a reason for hiding this comment

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

NIT: snip? Could a more descriptive variable name be used instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

Any suggestions in mind? :)

zulipterminal/ui_tools/buttons.py Outdated Show resolved Hide resolved
@rsashank rsashank force-pushed the codesnippet1123 branch 6 times, most recently from a7d3191 to 4268b0b Compare June 5, 2024 07:59
@rsashank
Copy link
Member Author

rsashank commented Jun 5, 2024

Thanks for the detailed feedback @Niloth-p!

I've updated the PR. I still need to figure out where the language data was tagged in the previous version of Zulip markup, but I believe everything else should be addressed now. :)

@rsashank rsashank added the PR needs review PR requires feedback to proceed label Jun 5, 2024
@rsashank rsashank force-pushed the codesnippet1123 branch 4 times, most recently from 59194bd to 33bfce1 Compare July 8, 2024 21:59
This was referenced Jul 19, 2024
@rsashank rsashank force-pushed the codesnippet1123 branch 2 times, most recently from b5e97e4 to dfb2e39 Compare September 19, 2024 17:12
rsashank and others added 3 commits September 19, 2024 22:47
Adjusted clipboard_text by replacing \r\n with \n to accommodate carriage
returns in WSL. Ensures consistent newline handling for comparison.
This prevents unnecessary "text does not match" warnings for WSL users when
copying texts containing newline characters.
This class inherits from urwid.Button and enables the creation of code
block buttons that copy code to the clipboard when activated.

Co-authored-by: kingjuno <[email protected]>
Co-authored-by: yuktasarode <[email protected]>
Updated existing tests. New test added.

Co-authored-by: kingjuno <[email protected]>
Co-authored-by: yuktasarode <[email protected]>
@rsashank rsashank force-pushed the codesnippet1123 branch 2 times, most recently from c46598b to 964c17a Compare September 19, 2024 17:21
Introduces support for copying code blocks in the message information
popup. Makes use of the CodeBlockButton class and its methods.
Tests added.

Co-authored-by: kingjuno <[email protected]>
Co-authored-by: yuktasarode <[email protected]>

Fixes zulip#1123.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers missing feature: user A missing feature for all users, present in another Zulip client PR needs mentor review PR needs review PR requires feedback to proceed size: XL [Automatic label added by zulipbot] version parity: 4
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for copying code snippets
4 participants