Skip to content

Commit

Permalink
Add underscore code action
Browse files Browse the repository at this point in the history
Created a code action that prepends an underscore to unused variable
names.
  • Loading branch information
scohen committed Nov 21, 2022
1 parent d8b9694 commit 5322d1d
Show file tree
Hide file tree
Showing 19 changed files with 721 additions and 40 deletions.
21 changes: 21 additions & 0 deletions apps/language_server/lib/language_server/experimental/code_unit.ex
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,31 @@ defmodule ElixirLS.LanguageServer.Experimental.CodeUnit do
do_to_utf16(binary, utf16_unit + 1, 0)
end

def count(:utf16, binary) do
do_count_utf16(binary, 0)
end

# Private

# UTF-16

def do_count_utf16(<<>>, count) do
count
end

def do_count_utf16(<<c, rest::binary>>, count) when c < 128 do
do_count_utf16(rest, count + 1)
end

def do_count_utf16(<<c::utf8, rest::binary>>, count) do
increment =
<<c::utf16>>
|> byte_size()
|> div(2)

do_count_utf16(rest, count + increment)
end

defp do_utf16_offset(_, 0, offset) do
offset
end
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
defmodule ElixirLS.LanguageServer.Experimental.Format.Diff do
alias ElixirLS.LanguageServer.Experimental.CodeUnit
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Position
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.Range
alias ElixirLS.LanguageServer.Experimental.Protocol.Types.TextEdit
Expand Down Expand Up @@ -79,16 +80,10 @@ defmodule ElixirLS.LanguageServer.Experimental.Format.Diff do
end

def advance(<<c::utf8, rest::binary>>, {line, unit}) do
increment = utf16_code_units(<<c::utf16>>)
increment = CodeUnit.count(:utf16, <<c::utf8>>)
advance(rest, {line, unit + increment})
end

def utf16_code_units(<<_::utf16>> = utf16_grapheme) do
utf16_grapheme
|> byte_size()
|> div(2)
end

defp edit(text, start_line, start_unit, end_line, end_unit) do
TextEdit.new(
new_text: text,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
defmodule ElixirLS.LanguageServer.Experimental.Protocol.Proto.Convert do
alias ElixirLS.LanguageServer.SourceFile
alias ElixirLS.LanguageServer.Experimental.Protocol.Types
alias ElixirLS.LanguageServer.Experimental.SourceFile.Conversions
alias ElixirLS.LanguageServer.Experimental.SourceFile

def to_elixir(%{text_document: _} = request) do
with {:ok, source_file} <- fetch_source_file(request.lsp),
{:ok, updates} <- convert(request.lsp, source_file) do
def to_elixir(%{lsp: lsp_request} = request) do
with {:ok, elixir_request, source_file} <- convert(lsp_request) do
updated_request =
request
|> Map.put(:source_file, source_file)
|> Map.merge(updates)
case Map.merge(request, Map.from_struct(elixir_request)) do
%_{source_file: _} = updated -> Map.put(updated, :source_file, source_file)
updated -> updated
end

{:ok, updated_request}
end
end

def to_elixir(%_request_module{lsp: lsp_request} = request) do
converted = Map.merge(request, Map.from_struct(lsp_request))
{:ok, converted}
end

def to_elixir(request) do
request = Map.merge(request, Map.from_struct(request.lsp))

Expand All @@ -32,19 +39,58 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Proto.Convert do
:error
end

defp convert(%{range: range}, source_file) do
with {:ok, ex_range} <- Conversions.to_elixir(range, source_file) do
{:ok, %{range: ex_range}}
defp convert(%_{text_document: _} = request) do
with {:ok, source_file} <- fetch_source_file(request),
{:ok, converted} <- convert(request, source_file) do
{:ok, converted, source_file}
end
end

defp convert(%{position: position}, source_file) do
with {:ok, ex_pos} <- Conversions.to_elixir(position, source_file) do
{:ok, %{position: ex_pos}}
end
defp convert(%_{} = request) do
{:ok, request, nil}
end

defp convert(%Types.Range{} = range, %SourceFile{} = source_file) do
Conversions.to_elixir(range, source_file)
end

defp convert(%Types.Position{} = pos, %SourceFile{} = source_file) do
Conversions.to_elixir(pos, source_file)
end

defp convert(%_struct{} = request, %SourceFile{} = source_file) do
kvps =
request
|> Map.from_struct()
|> Enum.reduce(request, fn {key, value}, request ->
{:ok, value} = convert(value, source_file)
Map.put(request, key, value)
end)

{:ok, Map.merge(request, kvps)}
end

defp convert(list, %SourceFile{} = source_file) when is_list(list) do
items =
Enum.map(list, fn item ->
{:ok, item} = convert(item, source_file)
item
end)

{:ok, items}
end

defp convert(%{} = map, %SourceFile{} = source_file) do
converted =
Map.new(map, fn {k, v} ->
{:ok, converted} = convert(v, source_file)
{k, converted}
end)

{:ok, converted}
end

defp convert(_, _) do
{:ok, %{}}
defp convert(item, %SourceFile{} = _) do
{:ok, item}
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Proto.Macros.Json do
|> Enum.flat_map(fn
# flatten the spread into the current map
{:.., value} when is_map(value) -> Enum.to_list(value)
{k, v} -> [{k, v}]
{k, v} -> [{camelize(k), v}]
end)
|> JasonVendored.Encode.keyword(opts)
end
Expand All @@ -29,6 +29,17 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Proto.Macros.Json do
defp get_field_value(struct, field_name) do
Map.get(struct, field_name)
end

def camelize(field_name) do
field_name
|> to_string()
|> Macro.camelize()
|> downcase_first()
end

defp downcase_first(<<c::binary-size(1), rest::binary>>) do
String.downcase(c) <> rest
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Requests do
alias ElixirLS.LanguageServer.Experimental.Protocol.Proto
alias ElixirLS.LanguageServer.Experimental.Protocol.Types

# Client -> Server request
defmodule Initialize do
use Proto

Expand All @@ -12,36 +13,44 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Requests do
locale: optional(string()),
root_path: optional(string()),
root_uri: string(),
initialization_options: optional(map_of(any())),
initialization_options: optional(any()),
trace: optional(string()),
workspace_folders: optional(Types.WorkspaceFolder),
workspace_folders: optional(list_of(Types.WorkspaceFolder)),
capabilities: optional(map_of(any()))
end

defmodule FindReferences do
use Proto

defrequest("textDocument/references", :exclusive,
defrequest "textDocument/references", :exclusive,
text_document: Types.TextDocument.Identifier,
position: Types.Position
)
end

defmodule Formatting do
use Proto

defrequest("textDocument/formatting", :exclusive,
defrequest "textDocument/formatting", :exclusive,
text_document: Types.TextDocument.Identifier,
options: Types.FormattingOptions
)
end

defmodule CodeAction do
use Proto

defrequest "textDocument/codeAction", :exclusive,
text_document: Types.TextDocument.Identifier,
range: Types.Range,
context: Types.CodeActionContext
end

# Server -> Client requests

defmodule RegisterCapability do
use Proto

defrequest("client/registerCapability", :shared,
defrequest "client/registerCapability", :shared,
registrations: optional(list_of(LspTypes.Registration))
)
end

use Proto, decoders: :requests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,10 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Responses do

defresponse optional(list_of(Types.TextEdit))
end

defmodule CodeAction do
use Proto

defresponse optional(list_of(Types.CodeAction))
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,25 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Types do
deftype uri: uri(), version: integer()
end

defmodule TextDocument.OptionalVersionedIdentifier do
use Proto

deftype uri: uri(), version: optional(integer())
end

defmodule TextDocument.ContentChangeEvent do
use Proto

deftype range: optional(Range), text: string()
end

defmodule TextDocument.Edit do
use Proto

deftype text_document: TextDocument.OptionalVersionedIdentifier,
edits: list_of(TextEdit)
end

defmodule CodeDescription do
use Proto

Expand Down Expand Up @@ -147,6 +160,13 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Types do
resource_operations: optional(list_of(ResourceOperationKind))
end

defmodule WorkspaceEdit do
use Proto

deftype document_changes: optional(list_of(TextDocument.Edit)),
changes: optional(map_of(list_of(TextEdit)))
end

defmodule DidChangeConfiguration.ClientCapabilities do
use Proto

Expand Down Expand Up @@ -436,4 +456,53 @@ defmodule ElixirLS.LanguageServer.Experimental.Protocol.Types do
use Proto
deftype uri: uri(), name: string()
end

defmodule Command do
use Proto

deftype title: string(),
command: string(),
arguments: optional(list_of(any()))
end

defmodule CodeActionKind do
use Proto

defenum empty: "",
quick_fix: "quickfix",
refactor: "refactor",
refactor_extract: "refactor.extract",
refactor_inline: "refactor.inline",
refactor_rewrite: "refactor.rewrite",
source: "source",
source_organize_imports: "source.organizeImports",
source_fix_all: "source.fixAll"
end

defmodule CodeActionTriggerKind do
use Proto

defenum invoked: 1,
automatic: 2
end

defmodule CodeActionContext do
use Proto

deftype diagnostics: list_of(Diagnostic),
only: optional(list_of(CodeActionKind)),
trigger_kind: optional(CodeActionTriggerKind)
end

defmodule CodeAction do
use Proto

deftype title: string(),
kind: optional(CodeActionKind),
diagnostics: optional(list_of(Diagnostic)),
is_preferred: optional(boolean()),
edit: optional(WorkspaceEdit),
command: optional(Command),
data: optional(any())
end
end
Loading

0 comments on commit 5322d1d

Please sign in to comment.