Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix get_project_path for multi-directory workspaces #472

Merged
merged 4 commits into from
Dec 8, 2018
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
93 changes: 93 additions & 0 deletions plugin/core/test_paths.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import unittest
import random
import string
from .test_windows import MockWindow, MockView
from .workspace import get_project_path

try:
from typing import List, Optional, Any, Iterable
assert List and Optional and Any and Iterable
except ImportError:
pass


def random_file_string():
return ''.join(
random.choice(
string.ascii_lowercase + string.digits + string.whitespace + "."
)
for _ in range(random.randint(3, 24))
)


def mock_file_group(root_dir: str, file_count: int):
out = []
for i in range(file_count):
out.append(MockView(root_dir + "/" + random_file_string()))
if random.random() > 0.9:
subcontents = mock_file_group(
root_dir + "/" + random_file_string(),
random.randint(1, file_count)
)
random.shuffle(subcontents)
out.extend(subcontents)
return out


class GetProjectPathTests(unittest.TestCase):

def test_unrelated_files_1(self):
window = MockWindow([
[
MockView("/etc/some_configuration_file"),
],
mock_file_group("/home/user/project_a", 10),
mock_file_group("/home/user_project_b", 10)
])

window.set_folders(["/home/user/project_a", "/home/user/project_b"])
self.assertEqual(get_project_path(window), None)

def test_unrelated_files_2(self):
window = MockWindow([
mock_file_group("/home/user/project_a", 10),
mock_file_group("/home/user_project_b", 10),
[
MockView("/etc/some_configuration_file"),
]
])

window.set_folders(["/home/user/project_a", "/home/user/project_b"])
self.assertEqual(get_project_path(window), "/home/user/project_a")

def test_single_project(self):
window = MockWindow([
mock_file_group("/home/user/project_a", 10)
])

window.set_folders(["/home/user/project_a"])
self.assertEqual(get_project_path(window), "/home/user/project_a")

def test_double_project(self):
window = MockWindow([
mock_file_group("/home/user/project_a", 10),
mock_file_group("/home/user/project_b", 10)
])

window.set_folders(["/home/user/project_a", "/home/user/project_b"])
self.assertEqual(get_project_path(window), "/home/user/project_a")

def test_triple_project(self):
window = MockWindow([
mock_file_group("/home/user/project_a", 10),
mock_file_group("/home/user/project_b", 10)
])

window.set_folders(["/home/user/project_a", "/home/user/project_b"])
self.assertEqual(get_project_path(window), "/home/user/project_a")

def test_no_project(self):
window = MockWindow([[MockView("/just/pick/the/current/directory.txt")]])
window.set_folders([])

self.assertEqual(get_project_path(window), "/just/pick/the/current")
74 changes: 53 additions & 21 deletions plugin/core/workspace.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,69 @@
import os
try:
from typing import List, Optional, Any
assert List and Optional and Any
from typing import List, Optional, Any, Iterable
assert List and Optional and Any and Iterable
except ImportError:
pass

from .logging import debug
# from .types import WindowLike
from .types import ViewLike


def get_filename_from_view(view: ViewLike) -> 'Optional[str]':
if not view:
debug("No view is active in current window")
return None # https://github.com/tomv564/LSP/issues/219
filename = view.file_name()
if not filename:
debug("Couldn't determine project directory since no folders are open",
"and the current file isn't saved on the disk.")
return filename


def get_directory_name(view: ViewLike) -> 'Optional[str]':
filename = get_filename_from_view(view)
if filename:
project_path = os.path.dirname(filename)
return project_path
return None


def find_path_among_multi_folders(folders: 'Iterable[str]',
view: ViewLike) -> 'Optional[str]':
filename = get_filename_from_view(view)
if not filename:
return None
folders = [os.path.realpath(f) for f in folders]
file = view.file_name()
if not file:
return None
file = os.path.realpath(file)
while file not in folders:
file = os.path.dirname(file)
if os.path.dirname(file) == file:
# We're at the root of the filesystem.
file = None
break
debug('project path is', file)
return file


def get_project_path(window: 'Any') -> 'Optional[str]':
"""
Returns the first project folder or the parent folder of the active view
Returns the project folder or the parent folder of the active view
"""
if len(window.folders()):
if not window:
return None
num_folders = len(window.folders())
if num_folders == 0:
return get_directory_name(window.active_view())
elif num_folders == 1:
folder_paths = window.folders()
return folder_paths[0]
else:
view = window.active_view()
if view:
filename = view.file_name()
if filename:
project_path = os.path.dirname(filename)
debug("Couldn't determine project directory since no folders are open!",
"Using", project_path, "as a fallback.")
return project_path
else:
debug("Couldn't determine project directory since no folders are open",
"and the current file isn't saved on the disk.")
return None
else:
debug("No view is active in current window")
return None # https://github.com/tomv564/LSP/issues/219
else: # num_folders > 1
return find_path_among_multi_folders(
window.folders(),
window.active_view())


def get_common_parent(paths: 'List[str]') -> str:
Expand Down