summaryrefslogtreecommitdiffstats
path: root/plugins/externaltools/tools/filelookup.py
blob: f256eea23cf12d118abe57b2b1f7f0b1d680c717 (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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# -*- coding: utf-8 -*-
#
#    Copyright (C) 2009-2010  Per Arneng <per.arneng@anyplanet.com>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

import os
from gi.repository import Gio, Gedit
from .functions import *


class FileLookup:
    """
    This class is responsible for looking up files given a part or the whole
    path of a real file. The lookup is delegated to providers wich use
    different methods of trying to find the real file.
    """

    def __init__(self, window):
        self.providers = []
        self.providers.append(AbsoluteFileLookupProvider())
        self.providers.append(BrowserRootFileLookupProvider(window))
        self.providers.append(CwdFileLookupProvider())
        self.providers.append(OpenDocumentRelPathFileLookupProvider())
        self.providers.append(OpenDocumentFileLookupProvider())

    def lookup(self, path):
        """
        Tries to find a file specified by the path parameter. It delegates to
        different lookup providers and the first match is returned. If no file
        was found then None is returned.

        path -- the path to find
        """
        found_file = None
        for provider in self.providers:
            found_file = provider.lookup(path)
            if found_file is not None:
                break

        return found_file


class FileLookupProvider:
    """
    The base class of all file lookup providers.
    """

    def lookup(self, path):
        """
        This method must be implemented by subclasses. Implementors will be
        given a path and will try to find a matching file. If no file is found
        then None is returned.
        """
        raise NotImplementedError("need to implement a lookup method")


class AbsoluteFileLookupProvider(FileLookupProvider):
    """
    This file tries to see if the path given is an absolute path and that the
    path references a file.
    """

    def lookup(self, path):
        if os.path.isabs(path) and os.path.isfile(path):
            return Gio.file_new_for_path(path)
        else:
            return None


class BrowserRootFileLookupProvider(FileLookupProvider):
    """
    This lookup provider tries to find a file specified by the path relative to
    the file browser root.
    """
    def __init__(self, window):
        self.window = window

    def lookup(self, path):
        root = file_browser_root(self.window)
        if root:
            real_path = os.path.join(root, path)
            if os.path.isfile(real_path):
                return Gio.file_new_for_path(real_path)

        return None


class CwdFileLookupProvider(FileLookupProvider):
    """
    This lookup provider tries to find a file specified by the path relative to
    the current working directory.
    """

    def lookup(self, path):
        try:
            cwd = os.getcwd()
        except OSError:
            cwd = os.getenv('HOME')

        real_path = os.path.join(cwd, path)

        if os.path.isfile(real_path):
            return Gio.file_new_for_path(real_path)
        else:
            return None


class OpenDocumentRelPathFileLookupProvider(FileLookupProvider):
    """
    Tries to see if the path is relative to any directories where the
    currently open documents reside in. Example: If you have a document opened
    '/tmp/Makefile' and a lookup is made for 'src/test2.c' then this class
    will try to find '/tmp/src/test2.c'.
    """

    def lookup(self, path):
        if path.startswith('/'):
            return None

        for doc in Gio.Application.get_default().get_documents():
            if doc.get_file().is_local():
                location = doc.get_file().get_location()
                if location:
                    rel_path = location.get_parent().get_path()
                    joined_path = os.path.join(rel_path, path)
                    if os.path.isfile(joined_path):
                        return Gio.file_new_for_path(joined_path)

        return None


class OpenDocumentFileLookupProvider(FileLookupProvider):
    """
    Makes a guess that the if the path that was looked for matches the end
    of the path of a currently open document then that document is the one
    that is looked for. Example: If a document is opened called '/tmp/t.c'
    and a lookup is made for 't.c' or 'tmp/t.c' then both will match since
    the open document ends with the path that is searched for.
    """

    def lookup(self, path):
        if path.startswith('/'):
            return None

        for doc in Gio.Application.get_default().get_documents():
            if doc.get_file().is_local():
                location = doc.get_file().get_location()
                if location and location.get_uri().endswith(path):
                    return location
        return None

# ex:ts=4:et: