summaryrefslogtreecommitdiff
path: root/server/src/matcher/find_result.lua
blob: dcf00c6612fe7dac905c7239525fc76bd2c39b5b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
local function isContainPos(obj, pos)
    if obj.start <= pos and obj.finish + 1 >= pos then
        return true
    end
    return false
end

local function findAtPos(results, pos)
    local res = {}
    for sources, object in pairs(results.sources) do
        if sources.type == 'multi-source' then
            for _, source in ipairs(sources) do
                if source.type ~= 'simple' and isContainPos(source, pos) then
                    res[#res+1] = {
                        object = object,
                        source = source,
                        range = source.finish - source.start,
                    }
                end
            end
        else
            local source = sources
            if source.type ~= 'simple' and isContainPos(source, pos) then
                res[#res+1] = {
                    object = object,
                    source = source,
                    range = source.finish - source.start,
                }
            end
        end
    end
    if #res == 0 then
        return nil
    end
    table.sort(res, function (a, b)
        return a.range < b.range
    end)
    return res[1].object, res[1].source
end

local function findClosePos(results, pos)
    local curDis = math.maxinteger
    local parent = nil
    for sources, object in pairs(results.sources) do
        if sources.type == 'multi-source' then
            for _, source in ipairs(sources) do
                if source.type ~= 'simple' then
                    local dis = pos - source.finish
                    if dis > 0 and dis < curDis then
                        curDis = dis
                        parent = object
                    end
                end
            end
        else
            local source = sources
            if source.type ~= 'simple' then
                local dis = pos - source.finish
                if dis > 0 and dis < curDis then
                    curDis = dis
                    parent = object
                end
            end
        end
    end
    if parent then
        -- 造个假的 DirtyName
        local source = {
            type = 'name',
            start = pos,
            finish = pos,
            [1]    = '',
        }
        local result = {
            type = 'field',
            parent = parent,
            key = '',
            source = source,
        }
        return result, source
    end
    return nil
end

return function (vm, pos, close)
    local results = vm.results
    if close then
        local obj, source = findAtPos(results, pos)
        if obj then
            return obj, source
        else
            return findClosePos(results, pos)
        end
    else
        return findAtPos(results, pos)
    end
end