Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 58 additions & 2 deletions src/document.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mutable struct Document
path::String
_content::String
_line_offsets::Union{Nothing,Vector{Int}}
_line_offsets2::Union{Nothing,Vector{Int}}
_open_in_editor::Bool
_workspace_file::Bool
cst::EXPR
Expand All @@ -14,8 +15,9 @@ mutable struct Document
function Document(uri::AbstractString, text::AbstractString, workspace_file::Bool, server = nothing)
path = uri2filepath(uri)
cst = CSTParser.parse(text, true)
doc = new(uri, path, text, nothing, false, workspace_file, cst, [], 0, true, server, nothing)
doc = new(uri, path, text, nothing, nothing, false, workspace_file, cst, [], 0, true, server, nothing)
get_line_offsets(doc)
get_line_offsets2!(doc)
cst.val = path
set_doc(doc.cst, doc)
setroot(doc, doc)
Expand All @@ -38,6 +40,8 @@ end

function set_text!(doc::Document, text)
doc._content = text
doc._line_offsets = nothing
doc._line_offsets2 = nothing
end

function set_open_in_editor(doc::Document, value::Bool)
Expand Down Expand Up @@ -93,6 +97,37 @@ end
get_offset(doc, p::Position) = get_offset(doc, p.line, p.character)
get_offset(doc, r::Range) = get_offset(doc, r.start):get_offset(doc, r.stop)

function get_offset2(doc::Document, line::Integer, character::Integer)
line_offsets = get_line_offsets2!(doc)
text = get_text(doc)

if line >= length(line_offsets)
error("Invalid arguments.")
return nextind(text, lastindex(text))
elseif line < 0
error("Invalid arguments.")
end

line_offset = line_offsets[line+1]

next_line_offset = line + 1 < length(line_offsets) ? line_offsets[line + 2] : nextind(text, lastindex(text))

pos = line_offset

while character>0
if UInt32(text[pos]) >= 0x010000
character -= 2
else
character -= 1
end
pos = nextind(text, pos)
end

ret = min(pos, next_line_offset)

return pos
end

# Note: to be removed
function obscure_text(s)
i = 1
Expand Down Expand Up @@ -142,6 +177,27 @@ function get_line_offsets(doc::Document, force = false)
return doc._line_offsets
end

function get_line_offsets2!(doc::Document, force = false)
if force || doc._line_offsets2 === nothing
doc._line_offsets2 = Int[1]
text = get_text(doc)
ind = firstindex(text)
while ind <= lastindex(text)
c = text[ind]
if c == '\n' || c == '\r'
if c == '\r' && ind + 1 <= lastindex(text) && text[ind + 1] == '\n'
ind += 1
end
push!(doc._line_offsets2, ind + 1)
end

ind = nextind(text, ind)
end
end

return doc._line_offsets2
end

function get_line_of(line_offsets::Vector{Int}, offset::Integer)
nlines = length(line_offsets)
if offset > last(line_offsets)
Expand All @@ -167,7 +223,7 @@ byte offset.
function get_position_at(doc::Document, offset::Integer)
offset > sizeof(get_text(doc)) && error("offset[$offset] > sizeof(content)[$(sizeof(get_text(doc)))]") # OK, offset comes from EXPR spans
line_offsets = get_line_offsets(doc)
line, ind = get_line_of(doc._line_offsets, offset)
line, ind = get_line_of(line_offsets, offset)
io = IOBuffer(get_text(doc))
seek(io, line_offsets[line])
character = 0
Expand Down
7 changes: 4 additions & 3 deletions src/requests/actions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,10 @@ function get_next_line_offset(x)
file, offset = get_file_loc(x)
# get next line after using_stmt
insertpos = -1
for i = 1:length(file._line_offsets) - 1
if file._line_offsets[i] < offset + x.span <= file._line_offsets[i + 1]
insertpos = file._line_offsets[i + 1]
line_offsets = get_line_offsets(file)
for i = 1:length(line_offsets) - 1
if line_offsets[i] < offset + x.span <= line_offsets[i + 1]
insertpos = line_offsets[i + 1]
end
end
return insertpos
Expand Down
44 changes: 22 additions & 22 deletions src/requests/textdocument.jl
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,10 @@ end
function _partial_update(doc::Document, tdcce::TextDocumentContentChangeEvent)
cst = getcst(doc)
insert_range = get_offset(doc, tdcce.range)
updated_text = edit_string(get_text(doc), insert_range, tdcce.text)
set_text!(doc, updated_text)
doc._line_offsets = nothing

applytextdocumentchanges(doc, tdcce)

updated_text = get_text(doc)

i1, i2, loc1, loc2 = get_update_area(cst, insert_range)
is = insert_size(tdcce.text, insert_range)
Expand Down Expand Up @@ -217,32 +218,31 @@ function get_update_area(cst, insert_range)
return i1, i2, loc1, loc2
end

function convert_lsrange_to_jlrange(doc::Document, range::Range)
start_offset_ls = get_offset2(doc, range.start.line, range.start.character)
stop_offset = get_offset2(doc, range.stop.line, range.stop.character)

text = get_text(doc)

# we use prevind for the stop value here because Julia stop values in
# a range are inclusive, while the stop value is exclusive in a LS
# range
return start_offset_ls:prevind(text, stop_offset)
end

function applytextdocumentchanges(doc::Document, tdcce::TextDocumentContentChangeEvent)
if ismissing(tdcce.range) && ismissing(tdcce.rangeLength)
# No range given, replace all text
set_text!(doc, tdcce.text)
else
editrange = get_offset(doc, tdcce.range)
set_text!(doc, edit_string(get_text(doc), editrange, tdcce.text))
end
doc._line_offsets = nothing
end
editrange = convert_lsrange_to_jlrange(doc, tdcce.range)

function edit_string(text, editrange, edit)
if first(editrange) == last(editrange) == 0
text = string(edit, text)
elseif first(editrange) == 0 && last(editrange) == sizeof(text) # OK, this branch is probably not needed
text = edit
elseif first(editrange) == 0
text = string(edit, text[nextind(text, last(editrange)):end])
elseif first(editrange) == last(editrange) == sizeof(text) # OK, this branch is probably not needed
text = string(text, edit)
elseif last(editrange) == sizeof(text) # OK, this branch is probably not needed
text = string(text[1:first(editrange)], edit)
else
text = string(text[1:first(editrange)], edit, text[min(lastindex(text), nextind(text, last(editrange))):end])
end
text = get_text(doc)

new_text = string(text[1:prevind(text, editrange.start)], tdcce.text, text[nextind(text, editrange.stop):lastindex(text)])

set_text!(doc, new_text)
end
end

function parse_all(doc::Document, server::LanguageServerInstance)
Expand Down