diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e43f626..37948a12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ * Making `torus` and `ellipsoid` primitive objects, rather than being defined implicitly. [#450](https://github.com/Haskell-Things/ImplicitCAD/issues/450) * Improved formatting of ExtOpenSCAD code [#472](https://github.com/Haskell-Things/ImplicitCAD/pull/472) * Fixing an issue where ImplicitCAD extended primitive objects were being exported to OpenSCAD where they aren't supported. + * Fixing relative imports to use the directory of the initial source file rather than the directory where `extopenscad` was called. # Version [0.4.1.0](https://github.com/Haskell-Things/ImplicitCAD/compare/v0.4.0.0...v0.4.1.0) (2023-12-18) diff --git a/Graphics/Implicit/ExtOpenScad.hs b/Graphics/Implicit/ExtOpenScad.hs index a734b44f..f2e6cb51 100644 --- a/Graphics/Implicit/ExtOpenScad.hs +++ b/Graphics/Implicit/ExtOpenScad.hs @@ -5,7 +5,7 @@ -- An executor, which parses openscad code, and executes it. module Graphics.Implicit.ExtOpenScad (runOpenscad) where -import Prelude(String, IO, ($), (<$>), pure, either, (.), Applicative, Bool(True)) +import Prelude(String, IO, ($), (<$>), pure, either, (.), Applicative, Bool(True), Maybe, maybe) import Graphics.Implicit.Definitions (SymbolicObj2, SymbolicObj3) @@ -28,10 +28,11 @@ import System.Directory (getCurrentDirectory) import Data.Foldable (traverse_) import Data.Text.Lazy (pack) +import System.FilePath (FilePath, takeDirectory) -- | Small wrapper of our parser to handle parse errors, etc. -runOpenscad :: ScadOpts -> [String] -> String -> IO (VarLookup, [SymbolicObj2], [SymbolicObj3], [Message]) -runOpenscad scadOpts constants source = do +runOpenscad :: ScadOpts -> [String] -> Maybe FilePath -> String -> IO (VarLookup, [SymbolicObj2], [SymbolicObj3], [Message]) +runOpenscad scadOpts constants filepath source = do (initialObjects, initialMessages) <- addConstants constants True let err :: Applicative f => ParseError -> f (VarLookup, [SymbolicObj2], [SymbolicObj3], [Message]) @@ -39,11 +40,12 @@ runOpenscad scadOpts constants source = do run :: [StatementI] -> IO (VarLookup, [SymbolicObj2], [SymbolicObj3], [Message]) run sts = rearrange <$> do let sts' = traverse_ runStatementI sts - path <- getCurrentDirectory + -- If we are given a filepath, use its directory, relative or absolute. + -- If there is no filepath given, then use the current directory of the process. + path <- maybe getCurrentDirectory (pure . takeDirectory) filepath let initState = CompState initialObjects [] path (_, w, s') <- runImplicitCadM scadOpts initState sts' pure (w, s') - either err run $ parseProgram "" source where rearrange :: ([Message], CompState) -> (VarLookup, [SymbolicObj2], [SymbolicObj3], [Message]) diff --git a/programs/extopenscad.hs b/programs/extopenscad.hs index 035d5a83..38f142af 100644 --- a/programs/extopenscad.hs +++ b/programs/extopenscad.hs @@ -10,7 +10,7 @@ -- Let's be explicit about what we're getting from where :) -import Prelude (Maybe(Just, Nothing), IO, Bool(True, False), FilePath, String, (<>), ($), readFile, fst, putStrLn, show, (>>=), return, unlines, filter, not, null, (||), (&&), (.), print) +import Prelude (Maybe(Just, Nothing), IO, Bool(True, False), FilePath, String, (<>), ($), readFile, fst, putStrLn, show, (>>=), return, unlines, filter, not, null, (||), (&&), (.), print, pure) -- Our Extended OpenScad interpreter import Graphics.Implicit (union, runOpenscad) @@ -173,7 +173,7 @@ run rawargs = do _ | Just file <- outputFile args -> Just $ guessOutputFormat file _ -> Nothing scadOpts = generateScadOpts args - openscadProgram = runOpenscad scadOpts (rawDefines args) content + openscadProgram = runOpenscad scadOpts (rawDefines args) (pure $ inputFile args) content if quiet args then return () diff --git a/programs/implicitsnap.hs b/programs/implicitsnap.hs index 5bef9bd1..ce694910 100644 --- a/programs/implicitsnap.hs +++ b/programs/implicitsnap.hs @@ -158,7 +158,7 @@ executeAndExport content callback maybeFormat = callbackS str msg = callback <> "([" <> BSL.toStrict (encode str) <> "," <> BSL.toStrict (encode msg) <> ",null,null]);" scadOptions = generateScadOpts - openscadProgram = runOpenscad scadOptions [] content + openscadProgram = runOpenscad scadOptions [] Nothing content in unsafePerformIO $ do s@(_, obj2s, obj3s, messages) <- openscadProgram diff --git a/tests/MessageSpec/Util.hs b/tests/MessageSpec/Util.hs index 07781956..726905d1 100644 --- a/tests/MessageSpec/Util.hs +++ b/tests/MessageSpec/Util.hs @@ -10,7 +10,7 @@ module MessageSpec.Util ) where -- be explicit about where we get things from. -import Prelude (String, Bool(False), IO, return) +import Prelude (String, Bool(False), IO, return, Maybe (Nothing)) -- Expressions, symbols, and values in the OpenScad language. import Graphics.Implicit.ExtOpenScad.Definitions (ScadOpts(ScadOpts), MessageType, Message(Message), SourcePosition) @@ -39,7 +39,7 @@ infixr 1 --> -- | An even smaller wrapper which runs a program, and only returns the generated messages. for the test suite. getOpenscadMessages :: ScadOpts -> [String] -> String -> IO [Message] getOpenscadMessages scadOpts constants source = do - (_, _, _, messages) <- runOpenscad scadOpts constants source + (_, _, _, messages) <- runOpenscad scadOpts constants Nothing source return messages oneMessage :: MessageType -> SourcePosition -> Text -> [Message] diff --git a/tests/ParserSpec/Statement.hs b/tests/ParserSpec/Statement.hs index 64523009..1706ebe8 100644 --- a/tests/ParserSpec/Statement.hs +++ b/tests/ParserSpec/Statement.hs @@ -122,4 +122,4 @@ statementSpec = do "module foo\n(\nbar\n)\n{}" --> single (NewModule (Symbol "foo") [(Symbol "bar", Nothing)] []) describe "identifiers" $ do it "accepts unicode" $ - "module 💩 () { }" --> single (NewModule (Symbol "💩") [] []) + "module 💩 () { }" --> single (NewModule (Symbol "💩") [] []) \ No newline at end of file diff --git a/tests/imports/child.scad b/tests/imports/child.scad new file mode 100644 index 00000000..503d6f1b --- /dev/null +++ b/tests/imports/child.scad @@ -0,0 +1 @@ +include ; \ No newline at end of file diff --git a/tests/imports/config.scad b/tests/imports/config.scad new file mode 100644 index 00000000..90f048f6 --- /dev/null +++ b/tests/imports/config.scad @@ -0,0 +1,3 @@ +foo=1; +bar=2; +baz=3; \ No newline at end of file diff --git a/tests/imports/neighbour.scad b/tests/imports/neighbour.scad new file mode 100644 index 00000000..0c4b2a64 --- /dev/null +++ b/tests/imports/neighbour.scad @@ -0,0 +1,3 @@ +include <./config.scad>; + +cube(foo,bar,baz); \ No newline at end of file diff --git a/tests/imports/relative/deep/grandparent.scad b/tests/imports/relative/deep/grandparent.scad new file mode 100644 index 00000000..957ab20e --- /dev/null +++ b/tests/imports/relative/deep/grandparent.scad @@ -0,0 +1 @@ +include <../parent.scad>; \ No newline at end of file diff --git a/tests/imports/relative/parent.scad b/tests/imports/relative/parent.scad new file mode 100644 index 00000000..69cdb326 --- /dev/null +++ b/tests/imports/relative/parent.scad @@ -0,0 +1,3 @@ +include <../config.scad>; + +cube(foo,bar,baz); \ No newline at end of file