From 47b1057aec7543a59745e4749f8731d632e121db Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 24 Feb 2025 12:12:47 +0100 Subject: [PATCH 1/2] started exploring logical folders --- .../uri/ILogicalSourceLocationResolver.java | 25 +++++++++++++++++++ .../uri/file/SystemPathURIResolver.java | 25 ++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/org/rascalmpl/uri/ILogicalSourceLocationResolver.java b/src/org/rascalmpl/uri/ILogicalSourceLocationResolver.java index 05f17c91303..75bdbb2c694 100644 --- a/src/org/rascalmpl/uri/ILogicalSourceLocationResolver.java +++ b/src/org/rascalmpl/uri/ILogicalSourceLocationResolver.java @@ -1,11 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2009-2025 CWI + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI + *******************************************************************************/ + package org.rascalmpl.uri; import java.io.IOException; import io.usethesource.vallang.ISourceLocation; +/** + * A logical resolver translates locations keyed by their scheme and (optionally) their authority + * to a lower level scheme. Logical resolvers may translate to other logical resolvers, but + * most of them map directly to a physical location like file:/// + */ public interface ILogicalSourceLocationResolver { ISourceLocation resolve(ISourceLocation input) throws IOException; String scheme(); String authority(); + + /** + * Some logical resolver may collect entries from more than one location, + * hence first resolving and then calling ISourceLocationInput.list(..) won't do. + * An example is the PATH:/// resolver. + */ + default String[] resolveList(ISourceLocation input) throws IOException { + return URIResolverRegistry.getInstance().listEntries(resolve(input)); + } } diff --git a/src/org/rascalmpl/uri/file/SystemPathURIResolver.java b/src/org/rascalmpl/uri/file/SystemPathURIResolver.java index 4a8f4abc6d2..dcd6c93e04d 100644 --- a/src/org/rascalmpl/uri/file/SystemPathURIResolver.java +++ b/src/org/rascalmpl/uri/file/SystemPathURIResolver.java @@ -14,6 +14,7 @@ package org.rascalmpl.uri.file; import java.io.File; +import java.io.IOException; import java.util.Arrays; import org.rascalmpl.uri.ILogicalSourceLocationResolver; @@ -32,7 +33,6 @@ public String scheme() { return "PATH"; } - @Override public ISourceLocation resolve(ISourceLocation input) { String thePath = System.getenv("PATH"); @@ -49,6 +49,29 @@ public ISourceLocation resolve(ISourceLocation input) { ; } + @Override + public String[] resolveList(ISourceLocation input) { + String thePath = System.getenv("PATH"); + if (thePath == null) { + return new String[0]; + } + + return Arrays.stream(thePath.split(File.pathSeparator)) + .map(FileURIResolver::constructFileURI) + .map(r -> URIUtil.getChildLocation(r, input.getPath())) + .filter(URIResolverRegistry.getInstance()::exists) + .flatMap(r -> { + try { + return Arrays.stream(URIResolverRegistry.getInstance().list(r)); + } + catch (IOException e) { + return null; + } + }) + .filter(o -> o != null) + .toArray(String[]::new); + } + @Override public String authority() { return ""; From b170e71d3ec7dfbb73488c6d6d0772c382ade302 Mon Sep 17 00:00:00 2001 From: "Jurgen J. Vinju" Date: Mon, 24 Feb 2025 15:31:18 +0100 Subject: [PATCH 2/2] implemented logical folders --- .../rascalmpl/uri/URIResolverRegistry.java | 20 ++++++++----- .../uri/file/SystemPathURIResolver.java | 28 +++++++++++-------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/org/rascalmpl/uri/URIResolverRegistry.java b/src/org/rascalmpl/uri/URIResolverRegistry.java index 4e55fc2d7bc..5503cc24c20 100644 --- a/src/org/rascalmpl/uri/URIResolverRegistry.java +++ b/src/org/rascalmpl/uri/URIResolverRegistry.java @@ -709,16 +709,22 @@ private boolean isRootLogical(ISourceLocation uri) { } public String[] listEntries(ISourceLocation uri) throws IOException { - uri = safeResolve(uri); - if (isRootLogical(uri)) { - // if it's a location without any path and authority - // we want to list possible authorities if it's a logical one - // (logical resolvers cannot handle this call themselves) - Map candidates = logicalResolvers.get(uri.getScheme()); - if (candidates != null) { + Map candidates = logicalResolvers.get(uri.getScheme()); + + if (candidates != null && !candidates.isEmpty()) { + // this is a logical uri. we defer to resolveList to allow for the logical resolver to concatenate from + // different sources. But not if the authority and the path are empty, then we list the available authorities + if (isRootLogical(uri) && candidates.size() > 1) { return candidates.keySet().toArray(new String[0]); } + + String auth = uri.hasAuthority() ? uri.getAuthority() : ""; + ILogicalSourceLocationResolver resolver = candidates.get(auth); + + return resolver.resolveList(uri); } + + uri = safeResolve(uri); ISourceLocationInput resolver = getInputResolver(uri.getScheme()); if (resolver == null) { diff --git a/src/org/rascalmpl/uri/file/SystemPathURIResolver.java b/src/org/rascalmpl/uri/file/SystemPathURIResolver.java index dcd6c93e04d..a0a79551c45 100644 --- a/src/org/rascalmpl/uri/file/SystemPathURIResolver.java +++ b/src/org/rascalmpl/uri/file/SystemPathURIResolver.java @@ -15,6 +15,7 @@ import java.io.File; import java.io.IOException; +import java.util.stream.Stream; import java.util.Arrays; import org.rascalmpl.uri.ILogicalSourceLocationResolver; @@ -33,15 +34,20 @@ public String scheme() { return "PATH"; } - @Override - public ISourceLocation resolve(ISourceLocation input) { + private Stream pathStream() { String thePath = System.getenv("PATH"); if (thePath == null) { - return input; + return Stream.empty(); } return Arrays.stream(thePath.split(File.pathSeparator)) .map(FileURIResolver::constructFileURI) + .filter(URIResolverRegistry.getInstance()::exists); + } + + @Override + public ISourceLocation resolve(ISourceLocation input) { + return pathStream() .map(r -> URIUtil.getChildLocation(r, input.getPath())) .filter(URIResolverRegistry.getInstance()::exists) .findFirst() @@ -51,18 +57,18 @@ public ISourceLocation resolve(ISourceLocation input) { @Override public String[] resolveList(ISourceLocation input) { - String thePath = System.getenv("PATH"); - if (thePath == null) { - return new String[0]; - } - - return Arrays.stream(thePath.split(File.pathSeparator)) - .map(FileURIResolver::constructFileURI) + return pathStream() .map(r -> URIUtil.getChildLocation(r, input.getPath())) .filter(URIResolverRegistry.getInstance()::exists) .flatMap(r -> { + // here we concatenate the `.list()` for all folders in the path try { - return Arrays.stream(URIResolverRegistry.getInstance().list(r)); + if (URIResolverRegistry.getInstance().isDirectory(r)) { + return Arrays.stream(URIResolverRegistry.getInstance().listEntries(r)); + } + else { + return Stream.empty(); + } } catch (IOException e) { return null;