Acorn.jl/src/row.jl

162 lines
3.4 KiB
Julia

#############
# ROW #
#############
"""Holds file true data and render data"""
mutable struct Row
"file data, a row of text"
chars::String
"a row of text as rendered on screen"
render::String
end
Row(s::String) = Row(s, "")
"""Update the `render` string using the `chars` string"""
function update!(row::Row)
# Count the number of tabs
tabs = 0
for c in row.chars
c == '\t' && (tabs += 1)
end
# Allocate an array of characters
updated = Array{Char, 1}(length(row.chars) + tabs*(configGet(:tab_stop)-1))
# copy the characters into the updated array
idx = 1
for i in 1:length(row.chars)
# replace tabs with spaces
if row.chars[i] == '\t'
updated[idx] = ' '
idx += 1
while idx % configGet(:tab_stop) != 0;
updated[idx] = ' ';
idx += 1
end
else
updated[idx] = row.chars[i]
idx += 1
end
end
row.render = join(updated[1:idx-1])
end
"""Convert a cursor position in the document to a rendered cursor position"""
function renderX(row::Row, cx::Int)
rx = 1
for i in 1:cx-1
# If there is a tab, move the cursor forward to the tab stop
if row.chars[i] == '\t'
rx += (configGet(:tab_stop) - 1) - (rx % configGet(:tab_stop))
end
rx += 1
end
rx
end
"""opposite of renderX: Convert a render position to a chars position"""
function charX(row::Row, rx::Int)
cur_rx = 1
for cx = 1:length(row.chars)
if row.chars[cx] == '\t'
cur_rx += (configGet(:tab_stop) - 1) - (cur_rx % configGet(:tab_stop))
end
cur_rx += 1
cur_rx > rx && return cx
end
cx
end
"""Insert a char or string into a string"""
function insert(s::String, i::Int, c::Union{Char,String})
if s == ""
string(c)
else
string(s[1:i-1], c, s[i:end])
end
end
"""Delete char from string"""
function delete(s::String, i::Int)
i < 1 || i > length(s) && return s
string(s[1:i-1], s[i+1:end])
end
"""Insert a char into the row at a given location"""
function insertChar!(row::Row, i::Int, c::Char)
row.chars = insert(row.chars, i, c)
update!(row)
end
"""Insert a tab into the row at a given location. Return the number of chars inserted"""
function insertTab!(row::Row, i::Int)
num_chars = 1
t = '\t'
# If we are using spaces, move ahead more
if configGet(:expandtab)
num_chars = configGet(:tab_stop) - (i % configGet(:tab_stop))
t = repeat(" ", num_chars)
end
row.chars = insert(row.chars, i, t)
update!(row)
# Used for positioning the cursor
return num_chars
end
"""Delete char from row"""
function deleteChar!(row::Row, i::Int)
row.chars = delete(row.chars, i)
update!(row)
end
"""
Add a row to the end of the document
initialize the row with the given string
"""
function appendRowString(row::Row, str::String)
row.chars = string(row.chars, str)
update!(row)
end
########
# ROWS #
########
"""type alias for Array{Row, 1}"""
Rows = Array{Row, 1}
"""delete all rows from a Rows"""
function clearRows(rows::Rows)
while length(rows) > 0
pop!(rows)
end
end
"""Add a row to the end of the document"""
function appendRow(rows::Rows, s::String)
row = Row(s)
update!(row)
push!(rows, row)
end
"""Convert all ROW data to a single string"""
function rowsToString(rows::Rows)
join(map(row -> row.chars, rows), '\n')
end