11

Pressing cmd + x without selecting text in other IDEs, cuts the complete line. Same goes for cmd + c which copies, instead of cutting. Otherwise, if some text is selected, only that region is cut.

How do I do this in XCode?

I added the following in the IDETextKeyBindingSet.plist to add cutting line and copying line functionality :

<key>My Custom Commands</key>
<dict>
    <key>Cut Current Line</key>
    <string>selectLine:, cut:</string>
    <key>Copy Current Line</key>
    <string>selectLine:, copy:</string>
</dict>

But obviously binding these to cmd + x (or c) doesn't allow cutting/copying selected region. I understand I can set it to some other keybinding. But, as a force of habit, cmd + x (or c) suits better.

Is there any way to do this? Maybe an extension?

[PS I asked the same question on StackOverflow, but realised, this is more apt place]

1
  • There's an extra </dict> at the end of the plist. You might want to remove that so that people don't accidentally mess up the plist file if they copy the above text. Commented May 27, 2020 at 8:26

2 Answers 2

11

That is correct. (Xcode 10)

  1. Add the entry for cut line and copy line in the IDETextKeyBindingSet.plist file
  2. Save the IDETextKeyBindingSet.plist
  3. Restart Xcode
  4. Set a key for the new command through xcode > preferences > key bindings > My Custom Commands
  5. Resolve conflicts

Example: /Applications/Xcode.app/Contents/Frameworks/IDEKit.framework/Versions/A/Resources/IDETextKeyBindingSet.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Cut and Copy</key>
    <dict>
        <key>Cut Current Line</key>
        <string>selectLine:, cut:</string>
        <key>Copy Current Line</key>
        <string>selectLine:, copy:</string>
    </dict>
    <key>Duplication</key>
    <dict>
        <key>Duplicate Current Line</key>
        <string>moveToBeginningOfLine:, deleteToEndOfLine:, yank:, insertNewline:, moveToBeginningOfLine:, yank:</string>
        <key>Duplicate Lines</key>
        <string>selectLine:, copy:, moveToEndOfLine:, insertNewline:, paste:, deleteBackward:</string>
        <key>Delete Line</key>
        <string>selectLine:, deleteBackward:</string>
    </dict>
</dict>
</plist>

Xcode keybinding (Cut and Copy): enter image description here

Xcode conflict resolve (Cut and Copy): enter image description here

3
  • 1
    I've didn't tried but I think it doesn't fit the need of either copy the line or the selected text. Am I wrong?
    – AnthoPak
    Commented Jun 10, 2019 at 15:26
  • 1
    I see what you mean, that's correct, it does not take into consideration if text has been selected or not. If the information is not useful I can remove this post.
    – Francois
    Commented Jun 11, 2019 at 16:08
  • 2
    What I usually do is I add shift to cut/copy keys to cut/copy a line instead of the selected text eg. | Copy selected text cmd+c | Cut selected text cmd+x | Copy line shift+cmd+c | Cut line shift+cmd+x
    – Francois
    Commented Jun 12, 2019 at 7:12
0

I've found a solution by combining Better Touch Tool and @Francois answer. It's possible to use a single shortcut that inspects the active element and triggers shortcut A if there is some text selected, and shortcut B if there isn't.

This example relies on having associated ⌘x with the native Cut action in Xcode and ⇧⌘x with Cut Current Line in the mentioned answer.

  1. In BTT, add an Xcode override (the left panel)
  2. Select Keyboard Shortcuts (the top panel)
  3. Create a new keyboard shortcut, e.g. ⌘x
  4. Add a new block in the right panel, and leave it as "No Action" and selected.
  5. Paste this there:
[
  {
    "BTTActionCategory" : 0,
    "BTTIsPureAction" : true,
    "BTTPredefinedActionType" : 330,
    "BTTPredefinedActionName" : "If Condition",
    "BTTIfConditionFormat" : "focused_element_details CONTAINS \"AXSelectedText (W):  \\\"\\\"\"",
    "BTTIfConditionData" : "YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGvEBYLDBMYICorLTQ4PT5BRUlOT1JYXGBiVSRudWxs0w0ODxAREl8QF05TQ29tcG91bmRQcmVkaWNhdGVUeXBlXxAPTlNTdWJwcmVkaWNhdGVzViRjbGFzcxABgAKAFdIUDxUXWk5TLm9iamVjdHOhFoADgBTUDxkaGxwdHh9fEBFOU1JpZ2h0RXhwcmVzc2lvbl8QEE5TTGVmdEV4cHJlc3Npb25fEBNOU1ByZWRpY2F0ZU9wZXJhdG9ygBOADoAEgBHVISIjJA8lJicoKVlOU09wZXJhbmReTlNTZWxlY3Rvck5hbWVfEBBOU0V4cHJlc3Npb25UeXBlW05TQXJndW1lbnRzgAaABRADgAiADVx2YWx1ZUZvcktleTrSIw8QLIAH0i4vMDFaJGNsYXNzbmFtZVgkY2xhc3Nlc18QEE5TU2VsZkV4cHJlc3Npb26jMDIzXE5TRXhwcmVzc2lvblhOU09iamVjdNIUDzU3oTaACYAM0w8jOTo7PFlOU0tleVBhdGiACxAKgApfEBdmb2N1c2VkX2VsZW1lbnRfZGV0YWlsc9IuLz9AXxAcTlNLZXlQYXRoU3BlY2lmaWVyRXhwcmVzc2lvbqM_MjPSLi9CQ15OU011dGFibGVBcnJheaNCRDNXTlNBcnJhedIuL0ZHXxATTlNLZXlQYXRoRXhwcmVzc2lvbqRGSDIzXxAUTlNGdW5jdGlvbkV4cHJlc3Npb27TSiMPS0xNXxAPTlNDb25zdGFudFZhbHVlgA8QAIAQXxAXQVhTZWxlY3RlZFRleHQgKFcpOiAgIiLSLi9QUV8QGU5TQ29uc3RhbnRWYWx1ZUV4cHJlc3Npb26jUDIz1A9TVFVWTExXWk5TTW9kaWZpZXJXTlNGbGFnc15OU09wZXJhdG9yVHlwZYASEGPSLi9ZWl8QFU5TSW5QcmVkaWNhdGVPcGVyYXRvcqNZWzNfEBNOU1ByZWRpY2F0ZU9wZXJhdG9y0i4vXV5fEBVOU0NvbXBhcmlzb25QcmVkaWNhdGWjXV8zW05TUHJlZGljYXRl0i4vRGGiRDPSLi9jZF8QE05TQ29tcG91bmRQcmVkaWNhdGWjY18zAAgAEQAaACQAKQAyADcASQBMAFEAUwBsAHIAeQCTAKUArACuALAAsgC3AMIAxADGAMgA0QDlAPgBDgEQARIBFAEWASEBKwE6AU0BWQFbAV0BXwFhAWMBcAF1AXcBfAGHAZABowGnAbQBvQHCAcQBxgHIAc8B2QHbAd0B3wH5Af4CHQIhAiYCNQI5AkECRgJcAmECeAJ_ApECkwKVApcCsQK2AtIC1gLfAuoC8gMBAwMDBQMKAyIDJgM8A0EDWQNdA2kDbgNxA3YDjAAAAAAAAAIBAAAAAAAAAGUAAAAAAAAAAAAAAAAAAAOQ",
    "BTTEnabled2" : 1,
    "BTTOrder" : 1076
  },
  {
    "BTTActionCategory" : 0,
    "BTTIsPureAction" : true,
    "BTTLayoutIndependentActionChar" : "x",
    "BTTShortcutToSend" : "56,55,7",
    "BTTEnabled2" : 1,
    "BTTOrder" : 1077
  },
  {
    "BTTActionCategory" : 0,
    "BTTIsPureAction" : true,
    "BTTPredefinedActionType" : 333,
    "BTTPredefinedActionName" : "Else",
    "BTTEnabled2" : 1,
    "BTTOrder" : 1078
  },
  {
    "BTTActionCategory" : 0,
    "BTTIsPureAction" : true,
    "BTTLayoutIndependentActionChar" : "x",
    "BTTShortcutToSend" : "55,7",
    "BTTEnabled2" : 1,
    "BTTOrder" : 1079
  },
  {
    "BTTActionCategory" : 0,
    "BTTIsPureAction" : true,
    "BTTPredefinedActionType" : 334,
    "BTTPredefinedActionName" : "END If Condition",
    "BTTEnabled2" : 1,
    "BTTOrder" : 1080
  }
]

The result should look like this: CMD + X forking shortcut

Here's the value used in the If clause for focused_element_details in case you add it manually:

AXSelectedText (W):  ""

The If block is the same for all shortcuts, so just copy and paste it.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .