Skip to content

Conversation

@iMostfa
Copy link
Contributor

@iMostfa iMostfa commented Dec 21, 2025

Resolves: #2145
along with: swiftlang/swift#86173

example.mov

Add Copy Objective-C Selector code action

Implements a new refactor action that allows users to copy Objective-C
selectors from Swift code. Adds the objcSelector SourceKitD request and
corresponding command handling in the language service.

If the approach is okay, i can go forward with adding/updating tests, lint..etc

Thanks

Copy link
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

Thanks for opening the PR. One thing I’m not entirely convinced about is whether this should be a refactoring actions that modifies the current source file. I would probably have implemented this as a code action that shows a message with the Objective-C selector name to the user via the window/showMessageRequest request if the client supports that request. What do you think about that approach?

@iMostfa iMostfa force-pushed the push-tpunonyzorpx branch 4 times, most recently from 44a8a3c to 67d3137 Compare December 22, 2025 11:56
@iMostfa
Copy link
Contributor Author

iMostfa commented Dec 22, 2025

@ahoppen
Thanks for the quick review !
yup, i think it's more convenient, and won't need to depend on workspace/executeCommand in the client.
i will work on modifying.

@iMostfa iMostfa force-pushed the push-tpunonyzorpx branch 2 times, most recently from 711ea33 to e37ec29 Compare December 23, 2025 00:12
@iMostfa
Copy link
Contributor Author

iMostfa commented Dec 23, 2025

Screen.Recording.2025-12-23.at.1.10.07.AM.mov

@ahoppen I tried to use window/showMessageRequest but i found that we won't provide any actions, So instead I used window/showMessage which works by just showing a message

e37ec29

After giving it more thought, I think it’s more useful to add the Objective-C selector as a comment rather than only showing it in a dialog.

The most common use case for this action is likely copying the selector to use it in an Objective-C file. While it’s possible to move the mouse and copy it from the dialog, it’s more convenient to stay on the keyboard and simply navigate to and select the comment.

Do you think it makes sense to prefer adding a comment in this case?

@ahoppen
Copy link
Member

ahoppen commented Dec 23, 2025

After giving it more thought, I think it’s more useful to add the Objective-C selector as a comment rather than only showing it in a dialog.

The most common use case for this action is likely copying the selector to use it in an Objective-C file. While it’s possible to move the mouse and copy it from the dialog, it’s more convenient to stay on the keyboard and simply navigate to and select the comment.

Do you think it makes sense to prefer adding a comment in this case?

My thoughts are that the Objective-C selector name is a transient bit of information that you are very unlikely to want to keep around in your source file. While I agree that copying may be easier if the selector gets added as a comment, I see two downsides (both not big, but still): We give a small indication that it may be a good pattern to keep the Objective-C selector of these functions around in your source file, which I don’t want to give. Furthermore, you need to remember to remove the comment again after copying the selector name. And doing so may counteract any workflow advantages from putting the selector in the source file.

@iMostfa
Copy link
Contributor Author

iMostfa commented Dec 23, 2025

fair points, so, if we decide to continue with just showMessage request, maybe we can rename the code action to be "Show Objective-c selector" instead of "Copy Objective-c selector" ?

@ahoppen
Copy link
Member

ahoppen commented Jan 3, 2026

can rename the code action to be "Show Objective-c selector" instead of "Copy Objective-c selector" ?

Absolutely!

@iMostfa iMostfa force-pushed the push-tpunonyzorpx branch 4 times, most recently from fb9b7a1 to fab55a4 Compare January 4, 2026 00:18
@iMostfa iMostfa changed the title Add Copy Objective-C Selector code action Add Show Objective-C Selector code action Jan 4, 2026
@iMostfa iMostfa force-pushed the push-tpunonyzorpx branch from fab55a4 to 9ad93db Compare January 4, 2026 00:19
@iMostfa iMostfa requested a review from ahoppen January 4, 2026 00:22
This updates the implementation to use `source.request.objc.selector`
directly instead of intercepting a refactoring action.

Changes:
- ShowObjCSelector.swift: Call `source.request.objc.selector` and read
  the selector from `key.text` in the response
- ShowObjCSelectorCommand.swift: Remove actionString field since we're
  not using refactoring
- SwiftLanguageService.swift: Show "Show Objective-C Selector" action
  for methods/functions/constructors instead of checking for a
  non-existent refactoring action
- sourcekitd_uids.swift: Add `objcSelector` UID for the new request

This aligns with swiftlang/swift#86173 which implements the feature as
a standalone request rather than a refactoring action.
Copy link
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

Nice, this looks good. Could you also add a test case for the new refactoring action? Both for the case where it shows and also a case checking that we don’t show it if the function doesn’t have an Objective-C selector.

Comment on lines +30 to +41
guard case .dictionary(let documentDict)? = dictionary[CodingKeys.textDocument.stringValue],
case .string(let title)? = dictionary[CodingKeys.title.stringValue],
case .dictionary(let rangeDict)? = dictionary[CodingKeys.positionRange.stringValue]
else {
return nil
}

guard let positionRange = Range<Position>(fromLSPDictionary: rangeDict),
let textDocument = TextDocumentIdentifier(fromLSPDictionary: documentDict)
else {
return nil
}
Copy link
Member

Choose a reason for hiding this comment

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

I think this can be simplified slightly by using init(fromLSPAny:)

Suggested change
guard case .dictionary(let documentDict)? = dictionary[CodingKeys.textDocument.stringValue],
case .string(let title)? = dictionary[CodingKeys.title.stringValue],
case .dictionary(let rangeDict)? = dictionary[CodingKeys.positionRange.stringValue]
else {
return nil
}
guard let positionRange = Range<Position>(fromLSPDictionary: rangeDict),
let textDocument = TextDocumentIdentifier(fromLSPDictionary: documentDict)
else {
return nil
}
guard let textDocument = TextDocumentIdentifier(fromLSPAny: dictionary[CodingKeys.textDocument.stringValue]),
case .string(let title)? = dictionary[CodingKeys.title.stringValue],
let positionRange = Range<Position>(fromLSPAny: dictionary[CodingKeys.positionRange.stringValue])
else {
return nil
}

Copy link
Member

Choose a reason for hiding this comment

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

Could you add the new files to CMakeLists.txt for the Windows build?

return methodKinds.contains(kind)
}
return false
}
Copy link
Member

Choose a reason for hiding this comment

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

Does this mean that we show the refactoring action on every Swift method, even if it isn’t backed by an Objective-C method and thus the Show Objective-C Selector would just fail? Do we have some indication in the cursor info response already to see whether this method is defined in Objective-C / that we have an Objective-C selector? One ugly idea I have is checking whether the USR starts with s: but there might be nicer implementations as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Action to Copy Objective-C Selector Name of @objc Swift Method

2 participants