Skip to content

Commit

Permalink
Fix: get_project_path for multi-directory workspaces (#472)
Browse files Browse the repository at this point in the history
* Fix #471
* Update workspace.py
* Add tests for get_project_path
  • Loading branch information
Dakota Thompson authored and rwols committed Dec 8, 2018
1 parent 5f9b914 commit b8109b1
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 21 deletions.
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

0 comments on commit b8109b1

Please sign in to comment.