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
17 changes: 5 additions & 12 deletions src/completions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -145,19 +145,14 @@ completionurl(c::REPLCompletions.ModuleCompletion) = begin
mod, name = c.parent, c.mod
val = getfield′(mod, name)
if val isa Module # module info
parentmodule(val) == val || val ∈ (Main, Base, Core) ?
"atom://julia-client/?moduleinfo=true&mod=$(name)" :
"atom://julia-client/?moduleinfo=true&mod=$(mod).$(name)"
urimoduleinfo(parentmodule(val) == val || val ∈ (Base, Core) ? name : "$mod.$name")
else
"atom://julia-client/?docs=true&mod=$(mod)&word=$(name)"
uridocs(mod, name)
end
end
completionurl(c::REPLCompletions.MethodCompletion) =
"atom://julia-client/?docs=true&mod=$(c.method.module)&word=$(c.method.name)"
completionurl(c::REPLCompletions.PackageCompletion) =
"atom://julia-client/?moduleinfo=true&mod=$(c.package)"
completionurl(c::REPLCompletions.KeywordCompletion) =
"atom://julia-client/?docs=true&mod=Main&word=$(c.keyword)"
completionurl(c::REPLCompletions.MethodCompletion) = uridocs(c.method.module, c.method.name)
completionurl(c::REPLCompletions.PackageCompletion) = urimoduleinfo(c.package)
completionurl(c::REPLCompletions.KeywordCompletion) = uridocs("Main", c.keyword)

completionmodule(mod, c) = shortstr(mod)
completionmodule(mod, c::REPLCompletions.ModuleCompletion) = shortstr(c.parent)
Expand All @@ -183,8 +178,6 @@ completiontype(::REPLCompletions.DictCompletion) = "property"
completiontype(::REPLCompletions.KeywordCompletion) = "keyword"
completiontype(::REPLCompletions.PathCompletion) = "path"

ismacro(ct::AbstractString) = startswith(ct, '@') || endswith(ct, '"')

completionicon(c) = ""
completionicon(c::REPLCompletions.ModuleCompletion) = begin
ismacro(c.mod) && return "icon-mention"
Expand Down
2 changes: 1 addition & 1 deletion src/docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function renderitem(x)

mod = getmodule(x.mod)
name = Symbol(x.name)
r[:typ], r[:icon], r[:nativetype] = if (name !== :ans || mod === Base) && name ∈ keys(Docs.keywords)
r[:typ], r[:icon], r[:nativetype] = if (name !== :ans || mod === Base) && iskeyword(name)
"keyword", "k", x.typ
else
val = getfield′(mod, name)
Expand Down
96 changes: 78 additions & 18 deletions src/utils.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# file utilities
# --------------

function isfile′(p)
try
isfile(p)
catch
false
end
end

iswritablefile(file) = Base.uperm(file) == 0x06
nonwritablefiles(files) = filter(!iswritablefile, files)

# path utilities
# --------------

include("path_matching.jl")

isuntitled(p) = occursin(r"^(\.\\|\./)?untitled-[\d\w]+(:\d+)?$", p)
Expand All @@ -12,14 +29,6 @@ function realpath′(p)
end
end

function isfile′(p)
try
isfile(p)
catch
false
end
end

using Pkg, OrderedCollections
function finddevpackages()
usage_file = joinpath(Pkg.logdir(), "manifest_usage.toml")
Expand Down Expand Up @@ -99,6 +108,9 @@ function md_hlines(md)
return MD(v)
end

# string utilties
# ---------------

function strlimit(str::AbstractString, limit::Int = 30, ellipsis::AbstractString = "…")
will_append = length(str) > limit

Expand All @@ -122,34 +134,56 @@ shortstr(val) = strlimit(string(val), 20)
struct Undefined end

# get utilities
# -------------

using CodeTools

"""
getfield′(mod::Module, name::String, default = Undefined())
getfield′(mod::Module, name::AbstractString, default = Undefined())
getfield′(mod::Module, name::Symbol, default = Undefined())
getfield′(mod::AbstractString, name::Symbol, default = Undefined())
getfield′(object, name::Symbol, default = Undefined())
getfield′(object, name::AbstractString, default = Undefined())

Returns the specified field of a given `Module` or some arbitrary `object`,
or `default` if no such a field is found.
"""
getfield′(mod::Module, name::String, default = Undefined()) = CodeTools.getthing(mod, name, default)
getfield′(mod::Module, name::AbstractString, default = Undefined()) = CodeTools.getthing(mod, name, default)
getfield′(mod::Module, name::Symbol, default = Undefined()) = getfield′(mod, string(name), default)
getfield′(mod::AbstractString, name::Symbol, default = Undefined()) = getfield′(getmodule(mod), string(name), default)
getfield′(@nospecialize(object), name::Symbol, default = Undefined()) = isdefined(object, name) ? getfield(object, name) : default
getfield′(@nospecialize(object), name::AbstractString, default = Undefined()) = isdefined(object, name) ? getfield(object, Symbol(name)) : default

"""
getmodule(mod::String)
getmodule(parent::Union{Nothing, Module}, mod::String)
getmodule(mod::AbstractString)
getmodule(parent::Union{Nothing, Module}, mod::AbstractString)
getmodule(code::AbstractString, pos; filemod)

Calls `CodeTools.getmodule(args...)`, but returns `Main` instead of `nothing` in a fallback case.
"""
getmodule(args...) = (m = CodeTools.getmodule(args...)) === nothing ? Main : m

getmethods(mod::Module, word::String) = methods(CodeTools.getthing(mod, word))
getmethods(mod::String, word::String) = getmethods(getmodule(mod), word)
"""
getmethods(mod::Module, word::AbstractString)
getmethods(mod::AbstractString, word::AbstractString)

Returns the [`MethodList`](@ref) for `word`, which is bound within `mod` module.
"""
getmethods(mod::Module, word::AbstractString) = methods(CodeTools.getthing(mod, word))
getmethods(mod::AbstractString, word::AbstractString) = getmethods(getmodule(mod), word)

"""
getdocs(mod::Module, word::AbstractString, fallbackmod::Module = Main)
getdocs(mod::AbstractString, word::AbstractString, fallbackmod::Module = Main)

Retrieves docs for `mod.word` with [`@doc`](@ref) macro. If `@doc` is not available
within `mod` module, `@doc` will be evaluated in `fallbackmod` module if possible.

getdocs(mod::Module, word::String, fallbackmod::Module = Main) = begin
md = if Symbol(word) in keys(Docs.keywords)
!!! note
You may want to run [`cangetdocs`](@ref) in advance.
"""
getdocs(mod::Module, word::AbstractString, fallbackmod::Module = Main) = begin
md = if iskeyword(word)
Core.eval(Main, :(@doc($(Symbol(word)))))
else
docsym = Symbol("@doc")
Expand All @@ -164,13 +198,39 @@ getdocs(mod::Module, word::String, fallbackmod::Module = Main) = begin
end
md_hlines(md)
end
getdocs(mod::String, word::String, fallbackmod::Module = Main) =
getdocs(mod::AbstractString, word::AbstractString, fallbackmod::Module = Main) =
getdocs(getmodule(mod), word, fallbackmod)

"""
cangetdocs(mod::Module, word::Symbol)
cangetdocs(mod::Module, word::AbstractString)
cangetdocs(mod::AbstractString, word::Union{Symbol, AbstractString})

Checks if the documentation bindings for `mod.word` is resolved and `mod.word`
is not deprecated.
"""
cangetdocs(mod::Module, word::Symbol) =
Base.isbindingresolved(mod, word) &&
!Base.isdeprecated(mod, word)
cangetdocs(mod::Module, word::String) = cangetdocs(mod, Symbol(word))
cangetdocs(mod::Module, word::AbstractString) = cangetdocs(mod, Symbol(word))
cangetdocs(mod::AbstractString, word::Union{Symbol, AbstractString}) = cangetdocs(getmodule(mod), word)

# is utilities
# ------------

iskeyword(word::Symbol) = word in keys(Docs.keywords)
iskeyword(word::AbstractString) = iskeyword(Symbol(word))

ismacro(ct::AbstractString) = startswith(ct, '@') || endswith(ct, '"')
ismacro(f::Function) = startswith(string(methods(f).mt.name), "@")

# uri utilties
# ------------

uriopen(file, line = 0) = "atom://julia-client/?open=true&file=$(file)&line=$(line)"
uridocs(mod, word) = "atom://julia-client/?docs=true&mod=$(mod)&word=$(word)"
urigoto(mod, word) = "atom://julia-client/?goto=true&mod=$(mod)&word=$(word)"
urimoduleinfo(mod) = "atom://julia-client/?moduleinfo=true&mod=$(mod)"

#=
module file detections
Expand Down
2 changes: 0 additions & 2 deletions src/workspace.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,3 @@ wsicon(mod, name, ::Expr) = "icon-code"
wsicon(mod, name, ::Symbol) = "icon-code"
wsicon(mod, name, ::Exception) = "icon-bug"
wsicon(mod, name, ::Undefined) = "icon-circle-slash"

ismacro(f::Function) = startswith(string(methods(f).mt.name), "@")
46 changes: 33 additions & 13 deletions test/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ end
@test Atom.finddevpackages() isa AbstractDict
end

#TODO: baselink, edit
# TODO: baselink, edit

cd(old_pwd)
end
Expand Down Expand Up @@ -79,18 +79,38 @@ end
end
end

@testset "limiting excessive strings" begin
using Atom: strlimit
@testset "is utilities" begin
@testset "iskeyword" begin
using Atom: iskeyword

# only including ASCII
@test strlimit("julia", 5) == "julia"
@test strlimit("julia", 4) == "jul…"
@test strlimit("Julia in the Nutshell", 21, " ...") == "Julia in the Nutshell"
@test strlimit("Julia in the Nutshell", 20, " ...") == "Julia in the Nut ..."
@test iskeyword(:begin)
@test iskeyword("begin")
@test !iskeyword(:iskeyword)
end

@testset "ismacro" begin
using Atom: ismacro

@test ismacro("@view")
@test ismacro("r\"")
@test ismacro(getfield(Main, Symbol("@view")))
end
end

# including Unicode: should respect _length_ of strings, not code units
@test strlimit("jμλια", 5) == "jμλια"
@test strlimit("jμλια", 4) == "jμλ…"
@test strlimit("Jμλια in the Nutshell", 21, " ...") == "Jμλια in the Nutshell"
@test strlimit("Jμλια in the Nutshell", 20, " ...") == "Jμλια in the Nut ..."
@testset "string utilities" begin
@testset "limiting excessive strings" begin
using Atom: strlimit

# only including ASCII
@test strlimit("julia", 5) == "julia"
@test strlimit("julia", 4) == "jul…"
@test strlimit("Julia in the Nutshell", 21, " ...") == "Julia in the Nutshell"
@test strlimit("Julia in the Nutshell", 20, " ...") == "Julia in the Nut ..."

# including Unicode: should respect _length_ of strings, not code units
@test strlimit("jμλια", 5) == "jμλια"
@test strlimit("jμλια", 4) == "jμλ…"
@test strlimit("Jμλια in the Nutshell", 21, " ...") == "Jμλια in the Nutshell"
@test strlimit("Jμλια in the Nutshell", 20, " ...") == "Jμλια in the Nut ..."
end
end