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

Retrie: implement high-level refactorings including renaming #282

Closed
pepeiborra opened this issue Aug 3, 2020 · 14 comments · Fixed by #2108
Closed

Retrie: implement high-level refactorings including renaming #282

pepeiborra opened this issue Aug 3, 2020 · 14 comments · Fixed by #2108
Assignees

Comments

@pepeiborra
Copy link
Collaborator

pepeiborra commented Aug 3, 2020

High-level refactorings should be doable by combining minimal code generation with retrie commands.

Rename

To rename foo to bar, proceed as follows:

  1. Rename foo to bar in place

  2. Generate a new declaration:

foo = bar
  1. Tell retrie to unfold foo

Move

Similar to rename, but in step 1 we move bar to the target module, while in step 2 we generate foo in the source module.

Extract definition

  1. Ask the user for the desired name
  2. Generate a new declaration with the desired name, using the selected subexpression as the function body, and the unbound variables as formal parameters
  3. Tell retrie to fold the new name
@sureyeaah
Copy link
Contributor

Does LSP support "asking user for a name"?

@Ailrun
Copy link
Member

Ailrun commented Aug 15, 2020

@sureyeaah I think that depends on LSP client, and LSP itself does not specify how to get a name for renaming.

@sureyeaah
Copy link
Contributor

sureyeaah commented Aug 15, 2020

@Ailrun right but does lsp support getting a string from a user, besides via a selection in the text buffer?

Edit: This is in context of extract refactoring (via codeaction)

@Ailrun
Copy link
Member

Ailrun commented Aug 15, 2020

At least LSP-mode (Emacs) supports that. IDK other clients though.

@sureyeaah
Copy link
Contributor

Is there something like that in the LSP spec?

@pepeiborra
Copy link
Collaborator Author

The LSP showMessageRequest supports some interaction with the user. If this is not enough, extract could assign a dummy name and let the user fix it later with a rename refactoring

@wz1000
Copy link
Collaborator

wz1000 commented Aug 16, 2020

IIRC, show message only accepting input from labeled buttons, and doesn't allow accepting arbitrary text.

@Ailrun
Copy link
Member

Ailrun commented Aug 16, 2020

textDocument/rename request accepts arbitrary text, and I think we should support this if we want to add the renaming feature.

@pepeiborra
Copy link
Collaborator Author

For rename I think the editor asks the user

@alanz
Copy link
Collaborator

alanz commented Aug 27, 2020

The only way to get a name is the rename command.

So the general workflow required is to say extract a function and give it some assigned name (newFunc3 or something) and then rename it.

@jneira jneira changed the title Retrie: implement high-level refactorings Retrie: implement high-level refactorings including renaming Sep 4, 2020
pepeiborra pushed a commit that referenced this issue Dec 27, 2020
* Support preprocessors

* Add a preprocessor for testing

* Add a preprocessor test
@OliverMadine
Copy link
Collaborator

OliverMadine commented Apr 9, 2021

@pepeiborra

Hello, I was hoping to tackle this project for this year's GSoC!

Could you please suggest what might be a good approach to step 1 (renaming in place)?

I initially had written some code to replace all references to the symbol in the current file:

descriptor :: PluginId -> PluginDescriptor IdeState
descriptor pluginId = (defaultPluginDescriptor pluginId) {
    pluginHandlers =  mconcat
        [ mkPluginHandler STextDocumentCodeLens codeLensProvider
        , mkPluginHandler STextDocumentRename renameProvider
        ]
}

renameProvider :: PluginMethodHandler IdeState TextDocumentRename
renameProvider
    state
    _pluginId
    (RenameParams tdi@(TextDocumentIdentifier uri) pos _progToken name)
        = do
            locs <- getTextEdits state tdi pos name
            return $ Right (WorkspaceEdit {
                _changes=Just $ singleton uri (List locs),
                _documentChanges=Nothing,
                _changeAnnotations=Nothing
            })

getTextEdits :: IdeState
    -> TextDocumentIdentifier
    -> Position
    -> T.Text
    -> LspT c IO [TextEdit]
getTextEdits state tdi@(TextDocumentIdentifier uri) pos name
    = do
        mbLocs <- references state $ ReferenceParams tdi pos Nothing Nothing (ReferenceContext False)
        case mbLocs of
            Right (List locs) -> return [TextEdit range name | Location uri' range <- locs, uri == uri']
            _                 -> return []

but when renaming types, this seems to replace too much code.

Am I correct to think Retrie.Replace will be better suited?

@pepeiborra
Copy link
Collaborator Author

Back when I opened this ticket references didn't exist and the suggestion was to use retrie, which is a powerful tool for performing code rewrites.

However now that we have references, that may well turn out to be the superior tool for implementing a rename refactoring since it is powered by a semantic database.

What retrie lacks is the semantic awareness, and what references doesn't give you is an engine to perform code rewrites. Therefore there are two open questions that you would need to consider:

  • Do you really need a code rewriting engine to perform renames?
  • Is there a way to connect retrie to hiedb (the semantic database) for more accurate rewrites?

@OliverMadine
Copy link
Collaborator

@pepeiborra

Thanks for the detailed explanation! References do seem to be a simple solution to most of the problem, but I'll need to consider how to manage some of the less obvious renames like qualified imports.

@jneira
Copy link
Member

jneira commented Jun 13, 2021

One of the points where renaming could be useful would be renaming on a diagnostic about duplicate definition (see #1532)

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

Successfully merging a pull request may close this issue.

7 participants