diff --git a/.gitignore b/.gitignore index 26629ae23f..88226596af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ -project/project +src/project/project src/project/build.properties +# do not commit + # Do not accidentally commit test files test/*.scala diff --git a/.travis.yml b/.travis.yml index f881790a1d..e3f1ccaac5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ - # +===============================================================+ # |THIS FILE HAS BEEN AUTO-GENERATED USING `sbt genTravisYML` | # |ANY CHANGES WILL BE OVERWRITTEN | @@ -13,199 +12,191 @@ env: - ENCRYPTION_LABEL: "25a07036478c" - COMMIT_AUTHOR_EMAIL: "tkw01536@gmail.com" -# using trusty and scala -dist: trusty -language: scala +# use java, and install sbt on OS X +language: java + + +# meta -- email notification for builds +notifications: + email: + on_success: change + on_failure: always + on_error: always + on_start: never + on_cancel: never + # speed up cloning of the git repository # we only need a clone depth of '1' git: depth: 1 - - -# everything below this line is automatically generated using the configuration in src/travis.sbt -stages: - - name: build.sbt - - name: CodeCheck - - name: DeployCheck - - name: test - - name: deploy - if: branch = master -jobs: - include: - # check that build.sbt loads - - stage: build.sbt - scala: 2.11.12 - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 exit)" - jdk: openjdk7 - env: - - INFO='Check that build.sbt loads' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 exit)" - scala: 2.11.12 - jdk: openjdk8 - env: - - INFO='Check that build.sbt loads' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 exit)" - scala: 2.11.12 - jdk: oraclejdk8 - env: - - INFO='Check that build.sbt loads' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 exit)" - scala: 2.11.12 - jdk: oraclejdk9 - env: - - INFO='Check that build.sbt loads' - # check that the code conforms to standards - - stage: CodeCheck - scala: 2.11.12 - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 compile)" - jdk: openjdk7 - env: - - INFO='Check that the code compiles' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 compile)" - scala: 2.11.12 - jdk: openjdk8 - env: - - INFO='Check that the code compiles' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 compile)" - scala: 2.11.12 - jdk: oraclejdk8 - env: - - INFO='Check that the code compiles' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 compile)" - scala: 2.11.12 - jdk: oraclejdk9 - env: - - INFO='Check that the code compiles' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 scalastyle)" - scala: 2.11.12 - jdk: openjdk7 - env: - - INFO='Print scalastyle violations' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 scalastyle)" - scala: 2.11.12 - jdk: openjdk8 - env: - - INFO='Print scalastyle violations' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 scalastyle)" - scala: 2.11.12 - jdk: oraclejdk8 - env: - - INFO='Print scalastyle violations' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 scalastyle)" - scala: 2.11.12 - jdk: oraclejdk9 - env: - - INFO='Print scalastyle violations' - # check that the 'apidoc', 'deploy' 'genTravisYML' and 'deployFull' targets work - - stage: DeployCheck - scala: 2.11.12 - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 deploy) && cd .. && [[ -f "deploy/mmt.jar" ]]' - jdk: openjdk7 - env: - - INFO='Check mmt.jar generation using `sbt deploy`' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 deploy) && cd .. && [[ -f "deploy/mmt.jar" ]]' - scala: 2.11.12 +# +===============================================================+ +# |Anything below this line has been generated automatically | +# |from src/travis.sbt. | +# +===============================================================+ +before_install: + - 'if [[ "$TRAVIS_OS_NAME" = "osx" ]]; then brew update; brew install sbt; fi' +before_script: + - 'if [ "$TRAVIS_BRANCH" == "devel" ]; then export TEST_USE_ARCHIVE_HEAD=1; fi' + - 'if [ "$TRAVIS_BRANCH" == "devel" ]; then export TEST_USE_DEVEL=1; fi' +install: + - "cd src && (cat /dev/null | sbt ++2.12.3 update) && cd .." +jobs: + include: + # check that 'sbt genTravisYML' has been run + - dist: trusty + env: + - "INFO='Check that `sbt genTravisYML` has been run'" + - 'SBT_VERSION_CMD="^validate"' jdk: openjdk8 - env: - - INFO='Check mmt.jar generation using `sbt deploy`' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 deploy) && cd .. && [[ -f "deploy/mmt.jar" ]]' - scala: 2.11.12 - jdk: oraclejdk8 - env: - - INFO='Check mmt.jar generation using `sbt deploy`' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 deploy) && cd .. && [[ -f "deploy/mmt.jar" ]]' - scala: 2.11.12 - jdk: oraclejdk9 - env: - - INFO='Check mmt.jar generation using `sbt deploy`' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 deployFull) && cd .. && [[ -f "deploy/mmt.jar" ]]' - scala: 2.11.12 - jdk: openjdk7 - env: - - INFO='Check mmt.jar generation using `sbt deployfull`' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 deployFull) && cd .. && [[ -f "deploy/mmt.jar" ]]' - scala: 2.11.12 + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 genTravisYML) && cd .." + - '(git diff --quiet --exit-code ".travis.yml")' + stage: SelfCheck + # Check that our tests run and the code compiles + - dist: trusty + env: + - "INFO='Check that the code compiles and the test runs run and the code compiles'" + - 'SBT_VERSION_CMD="^validate"' jdk: openjdk8 - env: - - INFO='Check mmt.jar generation using `sbt deployfull`' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 deployFull) && cd .. && [[ -f "deploy/mmt.jar" ]]' - scala: 2.11.12 + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 scalastyle) && cd .." + - "cd src && (cat /dev/null | sbt ++2.12.3 compile) && cd .." + - "cd src && (cat /dev/null | sbt ++2.12.3 test) && cd .." + stage: CompileAndCheck + - dist: trusty + env: + - "INFO='Check that the code compiles and the test runs run and the code compiles'" + - 'SBT_VERSION_CMD="^validate"' jdk: oraclejdk8 - env: - - INFO='Check mmt.jar generation using `sbt deployfull`' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 deployFull) && cd .. && [[ -f "deploy/mmt.jar" ]]' - scala: 2.11.12 + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 scalastyle) && cd .." + - "cd src && (cat /dev/null | sbt ++2.12.3 compile) && cd .." + - "cd src && (cat /dev/null | sbt ++2.12.3 test) && cd .." + - dist: trusty + env: + - "INFO='Check that the code compiles and the test runs run and the code compiles'" + - 'SBT_VERSION_CMD="^validate"' jdk: oraclejdk9 - env: - - INFO='Check mmt.jar generation using `sbt deployfull`' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 apidoc) && cd .. && [[ -d "apidoc" ]]' - scala: 2.11.12 - jdk: openjdk7 - env: - - INFO='Check that apidoc generation works' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 apidoc) && cd .. && [[ -d "apidoc" ]]' - scala: 2.11.12 + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 scalastyle) && cd .." + - "cd src && (cat /dev/null | sbt ++2.12.3 compile) && cd .." + - "cd src && (cat /dev/null | sbt ++2.12.3 test) && cd .." + # check that the 'apidoc', 'deploy' and 'deployFull' targets work + - dist: trusty + env: + - "INFO='Check mmt.jar generation using `sbt deploy`'" + - 'SBT_VERSION_CMD="^validate"' jdk: openjdk8 - env: - - INFO='Check that apidoc generation works' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 apidoc) && cd .. && [[ -d "apidoc" ]]' - scala: 2.11.12 + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 deploy) && cd .." + - '[[ -f "deploy/mmt.jar" ]]' + stage: DeployCheck + - dist: trusty + env: + - "INFO='Check mmt.jar generation using `sbt deploy`'" + - 'SBT_VERSION_CMD="^validate"' jdk: oraclejdk8 - env: - - INFO='Check that apidoc generation works' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 apidoc) && cd .. && [[ -d "apidoc" ]]' - scala: 2.11.12 + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 deploy) && cd .." + - '[[ -f "deploy/mmt.jar" ]]' + - dist: trusty + env: + - "INFO='Check mmt.jar generation using `sbt deploy`'" + - 'SBT_VERSION_CMD="^validate"' jdk: oraclejdk9 - env: - - INFO='Check that apidoc generation works' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 genTravisYML) && cd .. && (git diff --quiet --exit-code ".travis.yml")' - scala: 2.11.12 - jdk: openjdk7 - env: - - INFO='Check that `sbt genTravisYML` has been run' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 genTravisYML) && cd .. && (git diff --quiet --exit-code ".travis.yml")' - scala: 2.11.12 + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 deploy) && cd .." + - '[[ -f "deploy/mmt.jar" ]]' + - dist: trusty + env: + - "INFO='Check mmt.jar generation using `sbt deployfull`'" + - 'SBT_VERSION_CMD="^validate"' jdk: openjdk8 - env: - - INFO='Check that `sbt genTravisYML` has been run' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 genTravisYML) && cd .. && (git diff --quiet --exit-code ".travis.yml")' - scala: 2.11.12 + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 deployFull) && cd .." + - '[[ -f "deploy/mmt.jar" ]]' + - dist: trusty + env: + - "INFO='Check mmt.jar generation using `sbt deployfull`'" + - 'SBT_VERSION_CMD="^validate"' jdk: oraclejdk8 - env: - - INFO='Check that `sbt genTravisYML` has been run' - - script: 'cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 genTravisYML) && cd .. && (git diff --quiet --exit-code ".travis.yml")' - scala: 2.11.12 + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 deployFull) && cd .." + - '[[ -f "deploy/mmt.jar" ]]' + - dist: trusty + env: + - "INFO='Check mmt.jar generation using `sbt deployfull`'" + - 'SBT_VERSION_CMD="^validate"' jdk: oraclejdk9 - env: - - INFO='Check that `sbt genTravisYML` has been run' - # check that our own tests work - - stage: test - scala: 2.11.12 - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 test)" - jdk: openjdk7 - env: - - INFO='Run MMT Tests' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 test)" - scala: 2.11.12 + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 deployFull) && cd .." + - '[[ -f "deploy/mmt.jar" ]]' + - dist: trusty + env: + - "INFO='Check that apidoc generation works'" + - 'SBT_VERSION_CMD="^validate"' jdk: openjdk8 - env: - - INFO='Run MMT Tests' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 test)" - scala: 2.11.12 + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 apidoc) && cd .." + - '[[ -d "apidoc" ]]' + - dist: trusty + env: + - "INFO='Check that apidoc generation works'" + - 'SBT_VERSION_CMD="^validate"' jdk: oraclejdk8 - env: - - INFO='Run MMT Tests' - - script: "cd src && (cat /dev/null | sbt -Dsbt.scala.version=2.10.7 test)" - scala: 2.11.12 + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 apidoc) && cd .." + - '[[ -d "apidoc" ]]' + - dist: trusty + env: + - "INFO='Check that apidoc generation works'" + - 'SBT_VERSION_CMD="^validate"' jdk: oraclejdk9 - env: - - INFO='Run MMT Tests' + language: scala + scala: "2.12.3" + script: + - "cd src && (cat /dev/null | sbt ++2.12.3 apidoc) && cd .." + - '[[ -d "apidoc" ]]' # deploy the api documentation - - stage: deploy - scala: 2.11.12 - script: bash scripts/travis/deploy_doc.sh + - dist: trusty + env: + - "INFO='Auto-deploy API documentation'" + - 'SBT_VERSION_CMD="^validate"' jdk: openjdk8 - env: - - "INFO='Auto-deploy API documentation'" \ No newline at end of file + language: scala + scala: "2.12.3" + script: + - "bash scripts/travis/deploy_doc.sh" + stage: deploy +stages: + - name: SelfCheck + - name: CompileAndCheck + - name: DeployCheck + - if: "branch = master" + name: deploy \ No newline at end of file diff --git a/COPYING.txt b/COPYING.txt index 8f411b9f24..3853d7e348 100644 --- a/COPYING.txt +++ b/COPYING.txt @@ -6,7 +6,7 @@ See http://uniformal.github.io/doc/setup/license.html for the rationale behind t ---------------------------------------------------------------------------------------- -Copyright (c) 2016, Florian Rabe and contributors +Copyright (c) 2016-18, Florian Rabe and contributors All rights reserved. By contributing to this repository, contributors make their contribution subject to @@ -36,4 +36,4 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the respective authors and should not be interpreted as representing official policies, -either expressed or implied, of their organizations or funding agencies. \ No newline at end of file +either expressed or implied, of their organizations or funding agencies. diff --git a/deploy/.classpath b/deploy/.classpath index 31b3e8dde5..7597c6e57b 100644 --- a/deploy/.classpath +++ b/deploy/.classpath @@ -3,13 +3,6 @@ - - - - - - - diff --git a/deploy/lib/scala-compiler.jar b/deploy/lib/scala-compiler.jar index c281e9665b..50a16d8fa3 100644 Binary files a/deploy/lib/scala-compiler.jar and b/deploy/lib/scala-compiler.jar differ diff --git a/deploy/lib/scala-library.jar b/deploy/lib/scala-library.jar index 3bd0710244..b873f79264 100644 Binary files a/deploy/lib/scala-library.jar and b/deploy/lib/scala-library.jar differ diff --git a/deploy/lib/scala-parser-combinators.jar b/deploy/lib/scala-parser-combinators.jar index d75bc7d5ab..bd4a5e49f6 100644 Binary files a/deploy/lib/scala-parser-combinators.jar and b/deploy/lib/scala-parser-combinators.jar differ diff --git a/deploy/lib/scala-reflect.jar b/deploy/lib/scala-reflect.jar index 28695ae524..9e03045bf8 100644 Binary files a/deploy/lib/scala-reflect.jar and b/deploy/lib/scala-reflect.jar differ diff --git a/deploy/lib/scala-xml.jar b/deploy/lib/scala-xml.jar index 08740a2b63..fcd9fc8077 100644 Binary files a/deploy/lib/scala-xml.jar and b/deploy/lib/scala-xml.jar differ diff --git a/deploy/lib/tiscaf.jar b/deploy/lib/tiscaf.jar index 77250245c1..b5c4f7c915 100644 Binary files a/deploy/lib/tiscaf.jar and b/deploy/lib/tiscaf.jar differ diff --git a/deploy/mmt b/deploy/mmt index 80b534d4f1..e545979e67 100755 --- a/deploy/mmt +++ b/deploy/mmt @@ -1,3 +1,3 @@ #!/bin/bash dir="$(dirname $0)" -java -Xmx2048m -cp "$dir/lib/*:$dir/main/*" info.kwarc.mmt.api.frontend.Run "$@" +java -Xmx2048m -cp "$dir/lib/*:$dir/mmt.jar" info.kwarc.mmt.api.frontend.Run "$@" diff --git a/deploy/mmt.bat b/deploy/mmt.bat index 9febcbeb6b..d363e41e0a 100644 --- a/deploy/mmt.bat +++ b/deploy/mmt.bat @@ -1,4 +1,4 @@ @echo off rem This is the main extry point for running MMT on Windows. -java -Xmx1024m -cp %~dp0/lib/*;%~dp0/main/*;%~dp0/lfcatalog/lfcatalog.jar info.kwarc.mmt.api.frontend.Run %* +java -Xmx1024m -cp %~dp0/mmt.jar info.kwarc.mmt.api.frontend.Run %* diff --git a/scripts/logo/Makefile b/scripts/logo/Makefile index 5b17d2eba2..1000f535ac 100644 --- a/scripts/logo/Makefile +++ b/scripts/logo/Makefile @@ -1,4 +1,9 @@ -mmtlogo-1.svg: mmtlogo.tex - htlatex -scrollmode mmtlogo "xhtml,svg" - - +all: mmtlogo.svg +mmtlogo.svg: mmtlogo.tex + pdflatex --shell-escape mmtlogo.tex +mmtlogo.pdf: mmtlogo.tex + pdflatex mmtlogo.tex +clean: logclean + rm mmtlogo.svg +logclean: + rm *.aux *.log *.pdf diff --git a/scripts/logo/mmtlogo-1.svg b/scripts/logo/mmtlogo-1.svg deleted file mode 100644 index e17b92b672..0000000000 --- a/scripts/logo/mmtlogo-1.svg +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -M - - - - - - - - - -M - - - - - - - - - -T - - - - - - - - - - - - diff --git a/scripts/logo/mmtlogo.svg b/scripts/logo/mmtlogo.svg new file mode 100644 index 0000000000..0406c5a62e --- /dev/null +++ b/scripts/logo/mmtlogo.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/logo/mmtlogo.tex b/scripts/logo/mmtlogo.tex index d39d4c32d4..dce8475325 100644 --- a/scripts/logo/mmtlogo.tex +++ b/scripts/logo/mmtlogo.tex @@ -1,16 +1,13 @@ -\documentclass{article} -\usepackage{tikz} +\documentclass[crop,tikz,convert={outext=.svg,command=\unexpanded{pdf2svg \infile\space\outfile}},multi=false]{standalone}[2012/04/13] + \begin{document} -\thispagestyle{empty} \usetikzlibrary{decorations.pathmorphing,shapes,arrows} - % Taken from pgflibrarytikzmmt.code.tex - \newcommand{\mmtarrowtip}{angle 45} \newcommand{\mmtarrowtipmonoright}{right hook} \tikzstyle{include}=[\mmtarrowtipmonoright-\mmtarrowtip,thick] -\tikzstyle{morph}=[-\mmtarrowtip,thick] +\tikzstyle{morph}=[-\mmtarrowtip,thick] \tikzstyle{preview}=[decorate, decoration={coil,aspect=0,amplitude=1pt, segment length=6pt, pre=lineto,pre length=3pt, @@ -22,7 +19,7 @@ % White Background (Margins are eyeballed) % This is necessary because we paste white over arrows later. - % If somebody want's to do the full song and dance with + % If somebody want's to do the full song and dance with % interrupted arrows to get transparent background, be my guest. \fill[white!] (-0.01,0.15) rectangle (1.11,-0.95); diff --git a/src/build.sbt b/src/build.sbt index 4ada415c41..e3f8f20d7d 100644 --- a/src/build.sbt +++ b/src/build.sbt @@ -1,28 +1,52 @@ -import java.io.{BufferedWriter, FileWriter} - +import scala.io.Source import sbt.Keys._ +import scala.sys.process.Process +import scala.util.Try + // ================================= // META-DATA and Versioning // ================================= -version in ThisBuild := "1.0.1" -isSnapshot in ThisBuild := true +version in ThisBuild := {Source.fromFile("mmt-api/resources/versioning/system.txt").getLines.mkString.trim} + +val now = { + import java.text.SimpleDateFormat + import java.util.Date + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()) +} + + +packageOptions in Global ++= Seq( + // Specification Version can be any string, and hence includes the build time + Package.ManifestAttributes("Implementation-Version" -> (version.value + s" (built $now)")), + + // implementation version *has to be* ascii digits seperated by ascii periods + Package.ManifestAttributes("Specification-Version" -> version.value), + + // custom build-time attribute + Package.ManifestAttributes("Build-Time" -> now) +) + + organization in ThisBuild := "info.kwarc.mmt" +lazy val mmtMainClass = "info.kwarc.mmt.api.frontend.Run" // ================================= // GLOBAL SETTINGS // ================================= -scalaVersion in Global := "2.11.12" -scalacOptions in Global := Seq("-feature", "-deprecation", "-Xmax-classfile-name", "128") - -parallelExecution in ThisBuild := false -javaOptions in ThisBuild ++= Seq("-Xmx1g") +scalaVersion in Global := "2.12.3" +scalacOptions in Global := Seq( + "-feature", "-language:postfixOps", "-language:implicitConversions", "-deprecation", + "-Xmax-classfile-name", "128", // fix long classnames on weird filesystems + "-sourcepath", baseDirectory.value.getAbsolutePath // make sure that all scaladoc source paths are relative +) -connectInput in run := true -mainClass in Compile := Some("info.kwarc.mmt.api.frontend.Run") +parallelExecution in Global := false +javaOptions in Global ++= Seq("-Xmx2g") publish := {} fork in Test := true +testOptions in Test += Tests.Argument("-oI") // ================================= // DEPLOY TASKS @@ -40,7 +64,7 @@ scalacOptions in(ScalaUnidoc, unidoc) ++= Opts.doc.title("MMT") ++: Opts.doc.sourceUrl({ val repo = System.getenv("TRAVIS_REPO_SLUG") - s"https://github.com/${if(repo != null) repo else "UniFormal/MMT"}/blob/master€{FILE_PATH}.scala" + s"https://github.com/${if(repo != null) repo else "UniFormal/MMT"}/blob/master/src€{FILE_PATH}.scala" }) target in(ScalaUnidoc, unidoc) := file("../apidoc") @@ -61,13 +85,13 @@ def commonSettings(nameStr: String) = Seq( sourcesInBase := false, autoAPIMappings := true, exportJars := true, - libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.5" % "test", + libraryDependencies += "org.scalatest" % "scalatest_2.12" % "3.0.4" % "test", fork := true, test in assembly := {}, assemblyMergeStrategy in assembly := { case PathList("rootdoc.txt") | // 2 versions from from scala jars - PathList("META-INF", "MANIFEST.MF") => // should never be merged anyway + PathList("META-INF", _*) => // should never be merged anyway MergeStrategy.discard // work around weird behavior of default strategy, which renames files for no apparent reason case _ => MergeStrategy.singleOrError @@ -95,7 +119,7 @@ def mmtProjectsSettings(nameStr: String) = commonSettings(nameStr) ++ Seq( // ================================= import VersionSpecificProject._ lazy val excludedProjects = { - Exclusions(guidedTours, metamath) + Exclusions() .java7(repl, odk) .java9(concepts) } @@ -103,19 +127,21 @@ lazy val excludedProjects = { // ================================= // Main MMT Projects // ================================= + +// building API documentation lazy val src = (project in file(".")). enablePlugins(ScalaUnidocPlugin). exclusions(excludedProjects). aggregate( mmt, api, - leo, lf, concepts, tptp, owl, mizar, frameit, mathscheme, pvs, metamath, tps, imps, odk, specware, stex, webEdit, planetary, interviews, latex, openmath, oeis, repl, + lf, concepts, tptp, owl, mizar, frameit, mathscheme, pvs, metamath, tps, imps, odk, specware, stex, webEdit, planetary, interviews, latex, openmath, oeis, repl, tiscaf, lfcatalog, jedit ).settings( unidocProjectFilter in (ScalaUnidoc, unidoc) := excludedProjects.toFilter ) - +// This is the main project. 'mmt/deploy' compiles all relevants subprojects, builds a self-contained jar file, and puts into the deploy folder, from where it can be run. lazy val mmt = (project in file("mmt")). exclusions(excludedProjects). dependsOn(tptp, stex, pvs, specware, webEdit, oeis, odk, jedit, latex, openmath, imps, repl, concepts, interviews). @@ -127,23 +153,27 @@ lazy val mmt = (project in file("mmt")). assembly in Compile map Utils.deployTo(Utils.deploy / "mmt.jar") }.value, deployFull := deployFull.dependsOn(deploy).value, - mainClass in assembly := (mainClass in Compile).value, assemblyExcludedJars in assembly := { val cp = (fullClasspath in assembly).value cp filter { j => jeditJars.contains(j.data.getName) } }, - assemblyOption in assembly := (assemblyOption in assembly).value.copy( - prependShellScript = Some(Seq("#!/bin/bash", """exec /usr/bin/java -Xmx2048m -jar "$0" "$@""""))) + mainClass in Compile := Some(mmtMainClass), + connectInput in run := true, + mainClass in assembly := Some(mmtMainClass) ) // ================================= -// MMT Projects +// MMT Projects: central projects // ================================= +// MMT is split into multiple subprojects to that are managed independently. + +// The kernel upon which everything else depends. Maintainer: Florian lazy val api = (project in file("mmt-api")). settings(mmtProjectsSettings("mmt-api"): _*). settings( + scalacOptions in Compile ++= Seq("-language:existentials"), scalaSource in Compile := baseDirectory.value / "src" / "main", unmanagedJars in Compile += Utils.lib.toJava / "tiscaf.jar", unmanagedJars in Compile += Utils.lib.toJava / "scala-compiler.jar", @@ -155,28 +185,89 @@ lazy val api = (project in file("mmt-api")). unmanagedJars in Test += Utils.lib.toJava / "scala-reflect.jar", unmanagedJars in Test += Utils.lib.toJava / "scala-parser-combinators.jar", unmanagedJars in Test += Utils.lib.toJava / "scala-xml.jar", - libraryDependencies += "org.scala-lang" % "scala-parser-combinators" % "2.11.0-M4" % "test", +// libraryDependencies += "org.scala-lang" % "scala-parser-combinators" % scalaVersion.value % "test", libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value % "test", libraryDependencies += "org.scala-lang" % "scala-compiler" % scalaVersion.value % "test" ) +// Some foundation-specific extensions. Maintainer: Florian lazy val lf = (project in file("mmt-lf")). dependsOn(api % "compile -> compile; test -> test"). settings(mmtProjectsSettings("mmt-lf"): _*). settings( unmanagedJars in Compile += Utils.deploy.toJava / "lfcatalog" / "lfcatalog.jar", - libraryDependencies += "org.scala-lang" % "scala-parser-combinators" % "2.11.0-M4" % "test", +// libraryDependencies += "org.scala-lang" % "scala-parser-combinators" % "2.12.3" % "test", unmanagedJars in Test += Utils.lib.toJava / "tiscaf.jar" ) -lazy val leo = (project in file("mmt-leo")). - dependsOn(lf, api). - settings(mmtProjectsSettings("mmt-leo"): _*). +// ================================= +// MMT Projects: plugins for using MMT in other applications +// ================================= + +// jars to be used in Compile but not in the fat jar +val jeditJars = Seq( + "Console.jar", + "ErrorList.jar", + "Hyperlinks.jar", + "jedit.jar", + "SideKick.jar", + "jsr.jar" +) + +// using MMT inside jEdit. Maintainer: Florian +lazy val jedit = (project in file("jEdit-mmt")). + dependsOn(api, lf). + settings(commonSettings("jEdit-mmt"): _*). settings( - libraryDependencies += "com.assembla.scala-incubator" %% "graph-core" % "1.9.4" + scalaSource in Compile := baseDirectory.value / "src", + resourceDirectory in Compile := baseDirectory.value / "src/resources", + unmanagedJars in Compile ++= jeditJars map (baseDirectory.value / "lib" / _), + deploy := Utils.deployPackage("main/MMTPlugin.jar").value, + deployFull := Utils.deployPackage("main/MMTPlugin.jar").value, + install := Utils.installJEditJars ) + +// using MMT as a part of LaTeX. Maintainer: Florian +lazy val latex = (project in file("latex-mmt")). + dependsOn(stex). + settings(mmtProjectsSettings("latex-mmt"): _*) + +// using MMT in the OpenDreamKit project, includes language plugins for various systems such as GAP or Sage. Maintainer: Dennis +lazy val odk = (project in file("mmt-odk")). + dependsOn(api, lf). + settings(mmtProjectsSettings("mmt-odk"): _*) + +// using MMT in the planetary/MathHub systems. Orginally developed by Mihnea, functional but should be reviewed +lazy val planetary = (project in file("planetary-mmt")). + dependsOn(stex). + settings(mmtProjectsSettings("planetary-mmt"): _*) +// using MMT in the editing frontends. Orginally developed by Mihnea (?), functional but presumably obsolete +lazy val webEdit = (project in file("mmt-webEdit")). + dependsOn(stex). + settings(mmtProjectsSettings("mmt-webEdit"): _*) + +// MMT in the interview server. Maintainer: Teresa +lazy val interviews = (project in file("mmt-interviews")). + dependsOn(api, lf). + settings(mmtProjectsSettings("mmt-interviews"): _*) + +// ================================= +// MMT projects: additional (optional) functionality that is factored out into separate projects due to dependencies +// ================================= + +// auto-completion in the shell. Maintainer: Tom +lazy val repl = (project in file("mmt-repl")). + dependsOn(api). + settings(mmtProjectsSettings("mmt-repl")). + settings( + libraryDependencies ++= Seq( + "org.jline" % "jline" % "3.1.2" + ) + ) + +// alignment-based concept browser. Maintainer: Dennis lazy val concepts = (project in file("concept-browser")). dependsOn(api). settings(mmtProjectsSettings("concept-browser"): _*). @@ -186,8 +277,13 @@ lazy val concepts = (project in file("concept-browser")). ), unmanagedJars in Compile += Utils.lib.toJava / "tiscaf.jar", unmanagedJars in Compile += Utils.lib.toJava / "scala-xml.jar" - ) + ) + +// ================================= +// MMT Projects: plugins for working with other languages in MMT +// ================================= +// plugin for reading TPTP lazy val tptp = (project in file("mmt-tptp")). dependsOn(api, lf). settings(mmtProjectsSettings("mmt-tptp"): _*). @@ -195,6 +291,7 @@ lazy val tptp = (project in file("mmt-tptp")). unmanagedJars in Compile += baseDirectory.value / "lib" / "leo.jar" ) +// plugin for reading OWL. Originally developed by Füsun lazy val owl = (project in file("mmt-owl")). dependsOn(api, lf). settings(mmtProjectsSettings("mmt-owl"): _*). @@ -202,6 +299,7 @@ lazy val owl = (project in file("mmt-owl")). unmanagedJars in Compile += baseDirectory.value / "lib" / "owlapi-bin.jar" ) +// plugin for reading Mizar. Originally developed by Mihnea lazy val mizar = (project in file("mmt-mizar")). dependsOn(api, lf). settings(mmtProjectsSettings("mmt-mizar"): _*) @@ -210,94 +308,74 @@ lazy val frameit = (project in file("frameit-mmt")). dependsOn(api, lf). settings(mmtProjectsSettings("frameit-mmt"): _*) +// plugin for mathscheme-related functionality. Obsolete lazy val mathscheme = (project in file("mmt-mathscheme")). dependsOn(api, lf). settings(mmtProjectsSettings("mmt-mathscheme"): _*) +// plugin for reading PVS. Maintainer: Dennis lazy val pvs = (project in file("mmt-pvs")). dependsOn(api, lf). settings(mmtProjectsSettings("mmt-pvs"): _*) -lazy val mmscala = RootProject(uri("https://github.com/digama0/mm-scala.git#master")) +// plugin for reading metamath +lazy val mmscala = RootProject(uri("https://github.com/UniFormal/mm-scala#master")) lazy val metamath = (project in file("mmt-metamath")). dependsOn(api, lf, mmscala). settings(mmtProjectsSettings("mmt-metamath"): _*) +// plugin for reading TPS lazy val tps = (project in file("mmt-tps")). dependsOn(api, lf). settings(mmtProjectsSettings("mmt-tps"): _*) +// plugin for reading IMPS. Maintainer: Jonas lazy val imps = (project in file("mmt-imps")). dependsOn(api, lf). settings(mmtProjectsSettings("mmt-imps"): _*) -lazy val odk = (project in file("mmt-odk")). - dependsOn(api, lf). - settings(mmtProjectsSettings("mmt-odk"): _*) - +// plugin for reading specware. Maintainer: Florian lazy val specware = (project in file("mmt-specware")). dependsOn(api). settings(mmtProjectsSettings("mmt-specware"): _*) +// plugin for reading stex. Originally developed by Mihnea, currently dormant but functional lazy val stex = (project in file("mmt-stex")). dependsOn(api). settings(mmtProjectsSettings("mmt-stex"): _*) -lazy val guidedTours = (project in file("mmt-guidedTours")). - dependsOn(api). - settings(mmtProjectsSettings("mmt-guidedTours"): _*) - -lazy val webEdit = (project in file("mmt-webEdit")). - dependsOn(stex). - settings(mmtProjectsSettings("mmt-webEdit"): _*) - -lazy val planetary = (project in file("planetary-mmt")). - dependsOn(stex). - settings(mmtProjectsSettings("planetary-mmt"): _*) - -lazy val interviews = (project in file("mmt-interviews")). - dependsOn(api, lf). - settings(mmtProjectsSettings("mmt-interviews"): _*) - -lazy val latex = (project in file("latex-mmt")). - dependsOn(stex). - settings(mmtProjectsSettings("latex-mmt"): _*) - +// plugin for writing OpenMath CDs. Maintainer: Florian lazy val openmath = (project in file("mmt-openmath")). dependsOn(api). settings(mmtProjectsSettings("mmt-openmath"): _*) +// plugin for reading the OEIS lazy val oeis = (project in file("mmt-oeis")). dependsOn(planetary). settings(mmtProjectsSettings("mmt-oeis"): _*). settings( unmanagedJars in Compile += Utils.lib.toJava / "scala-parser-combinators.jar" ) - -lazy val repl = (project in file("mmt-repl")). - dependsOn(api). - settings(mmtProjectsSettings("mmt-repl")). - settings( - libraryDependencies ++= Seq( - "org.jline" % "jline" % "3.1.2" - ) - ) - + // ================================= -// DEPENDENT PROJECTS +// DEPENDENT PROJECTS (projects that do not use mmt-api) // ================================= +// this is a dependency of MMT that is copied into the MMT repository for convenience; it only has to be rebuilt when updated (which rarely happens) lazy val tiscaf = (project in file("tiscaf")). settings(commonSettings("tiscaf"): _*). settings( + scalacOptions in Compile ++= Seq("-language:reflectiveCalls"), scalaSource in Compile := baseDirectory.value / "src/main/scala", libraryDependencies ++= Seq( - "net.databinder.dispatch" %% "dispatch-core" % "0.11.3" % "test", +// "net.databinder.dispatch" %% "dispatch-core" % "0.11.3" % "test", "org.slf4j" % "slf4j-simple" % "1.7.12" % "test" ), - deployFull := Utils.deployPackage("lib/tiscaf.jar").value + deployFull := Utils.deployPackage("lib/tiscaf.jar").value, + test := {} // disable tests for tiscaf ) +// this is a dependency of Twelf if used in conjunction with the module system; it is automatically started when using the Twelf importer lazy val lfcatalog = (project in file("lfcatalog")). settings(commonSettings("lfcatalog")). settings( @@ -307,26 +385,13 @@ lazy val lfcatalog = (project in file("lfcatalog")). deployFull := Utils.deployPackage("lfcatalog/lfcatalog.jar").value ) -// experimental projects that are not part of any tests: marpa-mmt, hets-mmt - -// jars to be used in Compile but not in the fat jar -val jeditJars = Seq( - "Console.jar", - "ErrorList.jar", - "Hyperlinks.jar", - "jedit.jar", - "SideKick.jar", - "jsr.jar" -) - -lazy val jedit = (project in file("jEdit-mmt")). - dependsOn(api, lf). - settings(commonSettings("jEdit-mmt"): _*). - settings( - scalaSource in Compile := baseDirectory.value / "src", - resourceDirectory in Compile := baseDirectory.value / "src/resources", - unmanagedJars in Compile ++= jeditJars map (baseDirectory.value / "lib" / _), - deploy := Utils.deployPackage("main/MMTPlugin.jar").value, - deployFull := Utils.deployPackage("main/MMTPlugin.jar").value, - install := Utils.installJEditJars - ) +// ================================= +// experimental projects that are not part of the build file: +// +// hets-mmt: Aivaras's work for integrating with Hets, owned by DFKI but has become obsolete. +// marpa-mmt: +// mmt-guidedTours: obsolete +// mmt-leo: obsolete +// mmt-lfs: obsolete (has been merged into mmt-lf) +// mmt-reflection: obsolete (but worth keeping until it is superseded by foundations that handle it properly) +// ================================= diff --git a/src/concept-browser/src/info/kwarc/mmt/concepts/WebExtractors.scala b/src/concept-browser/src/info/kwarc/mmt/concepts/WebExtractors.scala index d931729e48..026a123b71 100644 --- a/src/concept-browser/src/info/kwarc/mmt/concepts/WebExtractors.scala +++ b/src/concept-browser/src/info/kwarc/mmt/concepts/WebExtractors.scala @@ -16,7 +16,7 @@ import org.ccil.cowan.tagsoup.jaxp.SAXFactoryImpl * - All exceptions thrown by MMT API must subclass api.Error. * - Retrieving children of XML elements is much simpler. * Use \\ to find non-direct children. - * id attributes are globally unique - it's unnecessary and less robust to chain id-based retrievals + * id attributes are globally unique - it's unnecessary and less robust to chain id-based retrievals */ abstract class WebExtractor { val scheme : String @@ -227,4 +227,4 @@ object NLabExtractor extends WebExtractor { h.literal(nret.mkString("")) } } -} \ No newline at end of file +} diff --git a/src/frameit-mmt/src/FrameIT.scala b/src/frameit-mmt/src/FrameIT.scala index 88c2386eff..644085b6c1 100644 --- a/src/frameit-mmt/src/FrameIT.scala +++ b/src/frameit-mmt/src/FrameIT.scala @@ -18,32 +18,32 @@ import scala.collection.immutable._ case class FrameitError(text : String) extends Error(text) class FrameViewer extends Extension { - + def pushout(cpath : CPath, vpaths : MPath*) : Term = { val comp = controller.get(cpath.parent) match { case c : Constant => cpath.component match { case DefComponent => c.df.getOrElse(throw FrameitError("No definition found for constant: " + cpath.parent)) - case TypeComponent => c.tp.getOrElse(throw FrameitError("No type found for constant: " + cpath.parent)) + case TypeComponent => c.tp.getOrElse(throw FrameitError("No type found for constant: " + cpath.parent)) } case s => throw FrameitError("Expected component term found " + s.toString) } pushout(comp, vpaths : _*) } - + def pushout(tm : Term, vpaths : MPath*) : Term = { vpaths.foldLeft(tm)((t, v) => pushoutOne(t, v)) } - + private def pushoutOne(tm : Term, vpath : MPath) : Term = { val view = controller.get(vpath) match { case v : DeclaredView => v case s => throw FrameitError("Expected view found " + s.toString) } - + val rules = makeRules(view) pushout(tm)(rules) } - + private def makeRules(v : DeclaredView) : HashMap[Path, Term]= { v.from match { case OMMOD(p) => @@ -62,15 +62,15 @@ class FrameViewer extends Extension { case _ => throw FrameitError("view.from not OMMOD " + v.from) } } - + private def pushout(t : Term)(implicit rules : HashMap[Path, Term]) : Term = t match { - case OMS(p) => + case OMS(p) => if (rules.isDefinedAt(p)) rules(p) else t case OMA(f, args) => OMA(pushout(f), args.map(pushout)) case OMBIND(b, con, body) => OMBIND(pushout(b), pushout(con), pushout(body)) case _ => t } - + private def pushout(con : Context)(implicit rules : HashMap[Path, Term]) : Context = con map (_ map pushout) } @@ -83,12 +83,12 @@ class FrameitPlugin extends ServerExtension("frameit") with Logger with MMTTask controller.extman.addExtension(a) a }//new FrameViewer(controller) - + /** Server */ /* private def CORS_AllowOrigin(origin : String) = true //for now - + private def checkCORS(tk : HTalk) : HTalk = tk.req.header("Origin") match { case None => tk case Some(s) => CORS_AllowOrigin(s) match { @@ -99,18 +99,18 @@ class FrameitPlugin extends ServerExtension("frameit") with Logger with MMTTask */ /* private def GetResponse : HLet = new HSimpleLet { - implicit val ec = scala.concurrent.ExecutionContext.Implicits.global + implicit val ec = scala.concurrent.ExecutionContext.Implicits.global def act(tk : HTalk) = try { val cpathS = tk.req.param("solPath").getOrElse(throw FrameitError("no solPath found")) val vpathS = tk.req.param("viewPath").getOrElse(throw FrameitError("no viewPath found")) - + val cpath = Path.parse(cpathS) match { case c : CPath => c case gn : GlobalName => CPath(gn, DefComponent) //assuming definition case p => throw FrameitError("Expected CPath or Global Name found " + p) } - + val vpath = Path.parse(vpathS) match { case vp : MPath => vp case p => throw FrameitError("Expected MPath found " + p) @@ -119,7 +119,7 @@ class FrameitPlugin extends ServerExtension("frameit") with Logger with MMTTask case d : DeclaredView => d case _ => throw FrameitError("expected view") } - + val tm = simplify(fv.pushout(cpath, vpath), view.to.toMPath) var tmS = tm.toString TextResponse(tmS).aact(tk) @@ -129,7 +129,7 @@ class FrameitPlugin extends ServerExtension("frameit") with Logger with MMTTask } } */ - + private def simplify(t : Term, home : MPath) : Term = { log("Before: " + t.toString) //val solver = new Solver(controller,cu,rules) @@ -172,17 +172,17 @@ class FrameitPlugin extends ServerExtension("frameit") with Logger with MMTTask val bodyArray: Array[Byte] = tk.req.octets.getOrElse(throw FrameitError("no body found")) new String(bodyArray, "UTF-8") } - + private def errorResponse(text : String) : HLet = { TextResponse(s"MMT Error in FrameIT extension: $text ") } - + /** * A text response that the server sends back to the browser * * @param text the message that is sent in the HTTP body */ - private def TextResponse(text: String): HLet = new HSimpleLet { + private def TextResponse(text: String): HLet = new HSimpleLet { def act(tk: HTalk) { val out = text.getBytes("UTF-8") checkCORS(tk).setContentLength(out.size) // if not buffered @@ -198,7 +198,7 @@ class FrameitPlugin extends ServerExtension("frameit") with Logger with MMTTask controller.extman.addExtension(ret) ret } - implicit val ce : CheckingEnvironment = new CheckingEnvironment(ErrorThrower,RelationHandler.ignore, this) + implicit val ce : CheckingEnvironment = new CheckingEnvironment(controller.simplifier,ErrorThrower,RelationHandler.ignore, this) val dpath = DPath(URI.http colon "cds.omdoc.org") / "FrameIT" val sitpath = dpath ? "situation_theory" @@ -347,7 +347,7 @@ class FrameitPlugin extends ServerExtension("frameit") with Logger with MMTTask val checker = new MMTStructureChecker(new RuleBasedChecker) controller.extman.addExtension(checker) - implicit val ce : CheckingEnvironment = new CheckingEnvironment(ErrorThrower,RelationHandler.ignore, this) + implicit val ce : CheckingEnvironment = new CheckingEnvironment(controller.simplifier,ErrorThrower,RelationHandler.ignore, this) controller.simplifier(view) controller.simplifier(sol) controller.simplifier(dom) @@ -370,5 +370,5 @@ class FrameitPlugin extends ServerExtension("frameit") with Logger with MMTTask //simplify(fv.pushout(cpath, vpath), view.to.toMPath) } - + } diff --git a/src/frameit-mmt/src/info/kwarc/mmt/frameit/Literals.scala b/src/frameit-mmt/src/info/kwarc/mmt/frameit/Literals.scala index f8a7201341..74d7dfdef2 100644 --- a/src/frameit-mmt/src/info/kwarc/mmt/frameit/Literals.scala +++ b/src/frameit-mmt/src/info/kwarc/mmt/frameit/Literals.scala @@ -25,9 +25,9 @@ import SemanticOperator._ // the corresponding .mmt files have to be adapted object DoubleFunctions { - + val R = StandardDouble // realizes Apply(OMS(tm),OMS(path ? "reals") - + object Negative extends Unary(R,R, {case R(x) => -x}) object Addition extends Binary(R,R,R, {case (R(x),R(y)) => x+y}) object Multiplication extends Binary(R,R,R, {case (R(x),R(y)) => x*y}) @@ -40,4 +40,4 @@ object DoubleFunctions { object Cosine extends Unary(R,R, {case R(x) => scala.math.cos(scala.math.toRadians(x))}) object ArcCosine extends Unary(R,R, {case R(x) => scala.math.acos(scala.math.toRadians(x))}) object SquareRoot extends Unary(R,R, {case R(x) => scala.math.sqrt(x)}) -} \ No newline at end of file +} diff --git a/src/hets-mmt/src/info/kwarc/mmt/hets/Exporter.scala b/src/hets-mmt/src/info/kwarc/mmt/hets/Exporter.scala index b160056cb9..896ca77ef1 100644 --- a/src/hets-mmt/src/info/kwarc/mmt/hets/Exporter.scala +++ b/src/hets-mmt/src/info/kwarc/mmt/hets/Exporter.scala @@ -9,87 +9,87 @@ import MyList._ import frontend._ /** - * exports an OMDoc theory (DeclaredTheory in controller lib) + * exports an OMDoc theory (DeclaredTheory in controller lib) * to a pseudo-XML file */ class Exporter(c : Controller = new Controller) { - val controller = c - - def insToNode(out : File, ins : Instance) : scala.xml.Node = { - - // get substituting terms - val args = ins.matches map {x => toNode(x)} - - // wrap instance declaration - - { args } - - } - - /** - * translates OM MMT objects to simplified XML nodes - */ - def toNode(t : Term) : scala.xml.Node = { - t match { - case OMV(n) => - case OMS(s) => s.name match { - case p / i => { - val ins : Instance = controller.globalLookup.get(GlobalName(s.module, LocalName(p))) match { - case x : Instance => x - case _ => throw GetError(GlobalName(s.module, LocalName(p)).toString + " is not an Instance") - } - - } - case i => - } - case OMA(OMS(s),args) => - - {args map(x => toNode(x))} - - case OMBIND(OMS(s),ctx,bd) => - ctx.variables.toList match { - case (VarDecl(v,None, None) :: Nil) => - {toNode(bd)} - case (VarDecl(v,Some(tp), None) :: Nil) => - {toNode(tp)} {toNode(bd)} - case _ => - } - - } - - } - - def compile(outDir : File, theory : DeclaredTheory) { - val outName = theory.name.toString + ".xml" - val instances = theory.components.mapPartial { x => x match { - case x : Instance => Some(x) - case _ => None - } - } - val out = File(outDir.toJava.getPath() + "/" + outName) - if (!outDir.toJava.exists()) { - println("creating dirs " + outDir.toJava.getPath()) - outDir.toJava.mkdirs() - } - val fw = new java.io.FileWriter(out.toJava.getPath()) - val ins = theory.getDeclarations.mapPartial { - case p: patterns.Instance => Some(p) - case _ => None - } - val nodes : List[scala.xml.Node]= ins map { - insToNode(out,_) - } - println("writing to file: " + out.toJava.getPath()) - println((nodes map {x => x.toString()}).mkString) - val pp = new scala.xml.PrettyPrinter(100,2) - val docNode = pp.format(nodes.head) - fw.write((nodes map {x => x.toString}).mkString("\n")) - fw.close() - } + val controller = c + + def insToNode(out : File, ins : Instance) : scala.xml.Node = { + + // get substituting terms + val args = ins.matches map {x => toNode(x)} + + // wrap instance declaration + + { args } + + } + + /** + * translates OM MMT objects to simplified XML nodes + */ + def toNode(t : Term) : scala.xml.Node = { + t match { + case OMV(n) => + case OMS(s) => s.name match { + case p / i => { + val ins : Instance = controller.globalLookup.get(GlobalName(s.module, LocalName(p))) match { + case x : Instance => x + case _ => throw GetError(GlobalName(s.module, LocalName(p)).toString + " is not an Instance") + } + + } + case i => + } + case OMA(OMS(s),args) => + + {args map(x => toNode(x))} + + case OMBIND(OMS(s),ctx,bd) => + ctx.variables.toList match { + case (VarDecl(v,None, None) :: Nil) => + {toNode(bd)} + case (VarDecl(v,Some(tp), None) :: Nil) => + {toNode(tp)} {toNode(bd)} + case _ => + } + + } + + } + + def compile(outDir : File, theory : DeclaredTheory) { + val outName = theory.name.toString + ".xml" + val instances = theory.components.mapPartial { x => x match { + case x : Instance => Some(x) + case _ => None + } + } + val out = File(outDir.toJava.getPath() + "/" + outName) + if (!outDir.toJava.exists()) { + println("creating dirs " + outDir.toJava.getPath()) + outDir.toJava.mkdirs() + } + val fw = new java.io.FileWriter(out.toJava.getPath()) + val ins = theory.getDeclarations.mapPartial { + case p: patterns.Instance => Some(p) + case _ => None + } + val nodes : List[scala.xml.Node]= ins map { + insToNode(out,_) + } + println("writing to file: " + out.toJava.getPath()) + println((nodes map {x => x.toString()}).mkString) + val pp = new scala.xml.PrettyPrinter(100,2) + val docNode = pp.format(nodes.head) + fw.write((nodes map {x => x.toString}).mkString("\n")) + fw.close() + } } -object ExporterTest { +object ExporterTest { def main(outDir : String, test : DeclaredTheory) = { new Exporter().compile(File(outDir),test) - } -} \ No newline at end of file + } +} diff --git a/src/hets-mmt/src/info/kwarc/mmt/hets/Main.scala b/src/hets-mmt/src/info/kwarc/mmt/hets/Main.scala index 7455f1c4d8..e3fd6cf697 100644 --- a/src/hets-mmt/src/info/kwarc/mmt/hets/Main.scala +++ b/src/hets-mmt/src/info/kwarc/mmt/hets/Main.scala @@ -1,175 +1,175 @@ -/** - * This is the main wrapper class for MMT. - * It imports main MMT class, parses twelf/spec files upon invocation, calls ' - * logic translation->abstract syntax->concrete syntax->Hets style logic definition' - * pipeline - * - * created by Aivaras: - * a.jakubauskas@jacobs-university.de - */ -package info.kwarc.mmt.hets - - -import info.kwarc.mmt.api._ -import utils.File._ //maybe the stuff here is useful -import backend.TextReader // the parser - -import info.kwarc.mmt.lf.compile._ - -import scala.util.control.Exception._ - -// for exception handling -import java.io.FileNotFoundException -import java.io.IOException -import utils._ -import utils.MyList._ -import modules._ -import patterns._ -import libraries._ -import frontend._ -import symbols._ -import objects._ -import objects.Conversions._ -import info.kwarc.mmt.api.frontend._ // for report -//import utils.MyList - - -import scala.sys.process._ - -//TODO implementation -/* + should be able to read in twelf files - * + twelf++ (typecheck and pattern match) the read files - * + read in pattern instance specification file (we have a logic + patterns already) - * - check the specifications, give sensible error messages if does not pass - */ -case class TheoryLookupError(msg : String) extends java.lang.Throwable(msg) - -object Main { - - val latinbase = "http://latin.omdoc.org/logics/syntax" - val foundational = "http://cds.omdoc.org/foundational" - val hetstest = "http://cds.omdoc.org/hets-test" - - def main(args: Array[String]) { - - if (args.length == 0) { - println("No arguments given. Expecting [flag] [filepath] arguments.\nTerminating.") - return - } - - try { - println("current dir " + getCurrentDir) - val flag = args(0) - println("flag: " + flag) - val filename = args(1) // take first argument - file name of the source - - //TODO make global - println("initiating controller") - val controller = new info.kwarc.mmt.api.frontend.Controller -// val uri = new utils.URI(None,None,List(hetstest + "?" + filename)) -// controller.handleLine("archive mmt source-structure") -// controller.handleLine("archive add /home/aivaras/TPTP/MMT/urtheories") -// controller.handleLine("archive add /home/aivaras/TPTP/MMT/test") - controller.handleLine("file /home/aivaras/TPTP/test/hets.msl").throwErrorIfAny() - - val fl = File(new java.io.File(filename)) - if (!(new java.io.File(filename).exists())) { - println("File " + filename + " does not exist!") - return - } - - val argl = args.toList - - // ===================================================== - if (argl contains "-newLogic") { - println("reading new logic") - println("..from file " + filename) - - // parse mmt doc - val source = scala.io.Source.fromFile(new java.io.File(filename),"UTF-8") - val (doc, err) = controller.read(File(new java.io.File(filename)), None) - //controller.textReader.readDocument(source, DPath(uri))(controller.termParser.apply(_)) - source.close() - if (!err.isEmpty) { - println("errors while reading " + filename + " encountered:") - err map println - return - } - // assume theory name is the same as file name - val thname = filename.substring(filename.lastIndexOf("/")+1, filename.lastIndexOf(".")) - - - // ----------- RUN ---------------------------- - -// println(controller.library.toString) - val theo = controller.localLookup.getTheory(DPath(utils.URI(hetstest)) ? thname) match { - case d : DeclaredTheory => d - case _ => throw TheoryLookupError("attempted retrieving not a DeclaredTheory") - } - println(theo) - val tls = new Theory2LogicSyntax() - println("translating " + thname + " to logic syntax") - val ls = tls.translateTheory(theo) - println(ls) - println("compiling pseudo-code") - - val dir : String = "/home/aivaras/Hets-src/" - - val lw = new LogicWriter(ls) - println("writing to files in " + dir + thname) - - lw.compile(ls, thname, dir) - - - println("new logic read and compiled") - controller.handleLine("exit") - } - // ======================================================== - else if (argl contains "-readSpec") { - // parse logic spec - println("reading logic specification") - val source = scala.io.Source.fromFile(new java.io.File(filename),"UTF-8") - val (doc, err) = controller.read(File(new java.io.File(filename)), None) - //controller.textReader.readDocument(source, DPath(uri))(controller.termParser.apply(_)) - source.close() - if (!err.isEmpty) { - println("errors while reading " + filename + " encountered:") - err map println - return - } else { - println("test") - println("no errors while reading") - println(doc.toString()) - val th = doc.getModulesResolved(controller.localLookup) foreach { - case t:DeclaredTheory => t - } - println(th.toString()) - } - println("..from file " + filename) - - } else { - - } - - - } // <------------ end of main - catch { - case e : java.lang.ArrayIndexOutOfBoundsException => println("Error: array index out of bounds") - e.printStackTrace() - - case e : java.lang.OutOfMemoryError => println("ran out of memory!") - e.printStackTrace() -// -// case e : FileNotFoundException => println("no such file: " + args(0) + ", check spelling") -// case e : IOException => println("IO exception") - case e : Throwable => println("unknown error:") - throw e - e.printStackTrace() - } - - - - } - - def getCurrentDir : String = new java.io.File( "." ).getCanonicalPath() -} \ No newline at end of file +/** + * This is the main wrapper class for MMT. + * It imports main MMT class, parses twelf/spec files upon invocation, calls ' + * logic translation->abstract syntax->concrete syntax->Hets style logic definition' + * pipeline + * + * created by Aivaras: + * a.jakubauskas@jacobs-university.de + */ +package info.kwarc.mmt.hets + + +import info.kwarc.mmt.api._ +import utils.File._ //maybe the stuff here is useful +import backend.TextReader // the parser + +import info.kwarc.mmt.lf.compile._ + +import scala.util.control.Exception._ + +// for exception handling +import java.io.FileNotFoundException +import java.io.IOException +import utils._ +import utils.MyList._ +import modules._ +import patterns._ +import libraries._ +import frontend._ +import symbols._ +import objects._ +import objects.Conversions._ +import info.kwarc.mmt.api.frontend._ // for report +//import utils.MyList + + +import scala.sys.process._ + +//TODO implementation +/* + should be able to read in twelf files + * + twelf++ (typecheck and pattern match) the read files + * + read in pattern instance specification file (we have a logic + patterns already) + * - check the specifications, give sensible error messages if does not pass + */ +case class TheoryLookupError(msg : String) extends java.lang.Throwable(msg) + +object Main { + + val latinbase = "http://latin.omdoc.org/logics/syntax" + val foundational = "http://cds.omdoc.org/foundational" + val hetstest = "http://cds.omdoc.org/hets-test" + + def main(args: Array[String]) { + + if (args.length == 0) { + println("No arguments given. Expecting [flag] [filepath] arguments.\nTerminating.") + return + } + + try { + println("current dir " + getCurrentDir) + val flag = args(0) + println("flag: " + flag) + val filename = args(1) // take first argument - file name of the source + + //TODO make global + println("initiating controller") + val controller = new info.kwarc.mmt.api.frontend.Controller +// val uri = new utils.URI(None,None,List(hetstest + "?" + filename)) +// controller.handleLine("archive mmt source-structure") +// controller.handleLine("archive add /home/aivaras/TPTP/MMT/urtheories") +// controller.handleLine("archive add /home/aivaras/TPTP/MMT/test") + controller.handleLine("file /home/aivaras/TPTP/test/hets.msl").throwErrorIfAny() + + val fl = File(new java.io.File(filename)) + if (!(new java.io.File(filename).exists())) { + println("File " + filename + " does not exist!") + return + } + + val argl = args.toList + + // ===================================================== + if (argl contains "-newLogic") { + println("reading new logic") + println("..from file " + filename) + + // parse mmt doc + val source = scala.io.Source.fromFile(new java.io.File(filename),"UTF-8") + val (doc, err) = controller.read(File(new java.io.File(filename)), None) + //controller.textReader.readDocument(source, DPath(uri))(controller.termParser.apply(_)) + source.close() + if (!err.isEmpty) { + println("errors while reading " + filename + " encountered:") + err map println + return + } + // assume theory name is the same as file name + val thname = filename.substring(filename.lastIndexOf("/")+1, filename.lastIndexOf(".")) + + + // ----------- RUN ---------------------------- + +// println(controller.library.toString) + val theo = controller.localLookup.getTheory(DPath(utils.URI(hetstest)) ? thname) match { + case d : DeclaredTheory => d + case _ => throw TheoryLookupError("attempted retrieving not a DeclaredTheory") + } + println(theo) + val tls = new Theory2LogicSyntax() + println("translating " + thname + " to logic syntax") + val ls = tls.translateTheory(theo) + println(ls) + println("compiling pseudo-code") + + val dir : String = "/home/aivaras/Hets-src/" + + val lw = new LogicWriter(ls) + println("writing to files in " + dir + thname) + + lw.compile(ls, thname, dir) + + + println("new logic read and compiled") + controller.handleLine("exit") + } + // ======================================================== + else if (argl contains "-readSpec") { + // parse logic spec + println("reading logic specification") + val source = scala.io.Source.fromFile(new java.io.File(filename),"UTF-8") + val (doc, err) = controller.read(File(new java.io.File(filename)), None) + //controller.textReader.readDocument(source, DPath(uri))(controller.termParser.apply(_)) + source.close() + if (!err.isEmpty) { + println("errors while reading " + filename + " encountered:") + err map println + return + } else { + println("test") + println("no errors while reading") + println(doc.toString()) + val th = doc.getModulesResolved(controller.localLookup) foreach { + case t:DeclaredTheory => t + } + println(th.toString()) + } + println("..from file " + filename) + + } else { + + } + + + } // <------------ end of main + catch { + case e : java.lang.ArrayIndexOutOfBoundsException => println("Error: array index out of bounds") + e.printStackTrace() + + case e : java.lang.OutOfMemoryError => println("ran out of memory!") + e.printStackTrace() +// +// case e : FileNotFoundException => println("no such file: " + args(0) + ", check spelling") +// case e : IOException => println("IO exception") + case e : Throwable => println("unknown error:") + throw e + e.printStackTrace() + } + + + + } + + def getCurrentDir : String = new java.io.File( "." ).getCanonicalPath() +} diff --git a/src/hets-mmt/src/info/kwarc/mmt/hets/SpecTest.scala b/src/hets-mmt/src/info/kwarc/mmt/hets/SpecTest.scala index 023f33bdee..3f60af1e68 100644 --- a/src/hets-mmt/src/info/kwarc/mmt/hets/SpecTest.scala +++ b/src/hets-mmt/src/info/kwarc/mmt/hets/SpecTest.scala @@ -1,9 +1,9 @@ /** * This is the main wrapper class for MMT. * It imports main MMT class, parses twelf/spec files upon invocation, calls ' - * logic translation->abstract syntax->concrete syntax->Hets style logic definition' + * logic translation->abstract syntax->concrete syntax->Hets style logic definition' * pipeline - * + * * created by Aivaras: * a.jakubauskas@jacobs-university.de */ @@ -33,54 +33,54 @@ import info.kwarc.mmt.api.frontend._ // for report object SpecTest { - + def main(args: Array[String]) { - + if (args.length == 0) { - println("No arguments given. Expecting 'flag filepath' [-outDir filepath] arguments.\nTerminating.") - return - } - try { - val argl = args.toList - val controller = new frontend.Controller + println("No arguments given. Expecting 'flag filepath' [-outDir filepath] arguments.\nTerminating.") + return + } + try { + val argl = args.toList + val controller = new frontend.Controller controller.handleLine("file startup.msl").throwErrorIfAny() -// if ( argl.length == 1) { +// if ( argl.length == 1) { // controller.handleLine(argl.head) // } - + val flag = args(0) println("flag: " + flag) - + val filename = args(1) // take first argument - file name of the source var outDir = "../../../test/source/hets-test" - if (args.contains("-outDir")) { outDir = args(args.length - 1) } - + if (args.contains("-outDir")) { outDir = args(args.length - 1) } + //TODO make global - - + + val fl = File(new java.io.File(filename)) if (!(new java.io.File(filename).exists())) { println("File " + filename + " does not exist!") return } - - - if (argl contains "-readSpec") { + + + if (argl contains "-readSpec") { // parse logic spec println("reading logic specification") println("\t\t..from file " + filename) val (doc, err) = controller.read(fl, None) if (!err.isEmpty) { - println("errors while reading " + filename + " encountered:") - err map println - return + println("errors while reading " + filename + " encountered:") + err map println + return } else { println("no errors while reading") val q = {doc.getModulesResolved(controller.localLookup) mapPartial { case t:DeclaredTheory => Some(t) case _ => None - } }.head + } }.head val xmlExp = new Exporter(controller) // export to XML xmlExp.compile(File(outDir),q) } @@ -88,9 +88,9 @@ object SpecTest { println(".... test test ....") val (doc, err) = controller.read(fl,None) if (!err.isEmpty) { - println("errors while reading " + filename + " encountered:") - err map println - return + println("errors while reading " + filename + " encountered:") + err map println + return } else { println("spec test") println("no errors while reading") @@ -101,16 +101,16 @@ object SpecTest { } println(th.toString()) } - + } // <------------ end of main - + catch { case e : java.lang.ArrayIndexOutOfBoundsException => println("Error: array index out of bounds") - e.printStackTrace() + e.printStackTrace() case e : Throwable => println("unknown error at SpecTest:"); throw e } - - - + + + } -} \ No newline at end of file +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Asset.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Asset.scala index 92f5f86c96..b3bef1b43a 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Asset.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Asset.scala @@ -2,6 +2,8 @@ package info.kwarc.mmt.jedit import sidekick._ +import org.gjt.sp.jedit._ + import info.kwarc.mmt.api._ import parser._ import objects._ @@ -16,13 +18,15 @@ case class MyPosition(offset : Int) extends javax.swing.text.Position { /** node in the sidekick outline tree: common ancestor class * @param name the label of the asset * @param region the source region of the asset - */ -sealed abstract class MMTAsset(name: String, val region: SourceRegion) - extends enhanced.SourceAsset(name, region.start.line, MyPosition(region.start.offset)) { + */ +sealed abstract class MMTAsset(name: String, val region: SourceRegion) extends enhanced.SourceAsset(name, region.start.line, MyPosition(region.start.offset)) { setEnd(MyPosition(region.end.offset+1)) /** the base URIto use in the context of this asset */ def getScope : Option[MPath] + /** can be used with TextArea.setSelection to select this asset */ + def toSelection = new textarea.Selection.Range(region.start.offset, region.end.offset+1) + // this line is helpful for debugging: it shows the source regions in the sidekick tree // setShort(name + " [" + region.toString + "]") } @@ -39,7 +43,7 @@ class MMTURIAsset(val path: Path, r: SourceRegion) extends MMTAsset(path.last, r /** node for structural elements * @param elem the node in the MMT syntax tree - */ + */ class MMTElemAsset(val elem : StructuralElement, name: String, reg: SourceRegion) extends MMTAsset(name, reg) { //note: shortDescription == name, shown in tree setLongDescription(path.toPath) // tool tip @@ -60,17 +64,30 @@ class MMTElemAsset(val elem : StructuralElement, name: String, reg: SourceRegion * @param term the node in the MMT syntax tree * @param parent the component containing the term * @param subobjectPosition the position in that term - */ -class MMTObjAsset(val obj: Obj, val pragmatic: Obj, val context: Context, val parent: CPath, name: String, reg: SourceRegion) extends MMTAsset(name, reg) { - obj.head map {case p => - setLongDescription(p.toPath) - } + */ +class MMTObjAsset(mmtplugin: MMTPlugin, val obj: Obj, val pragmatic: Obj, val context: Context, val parent: CPath, name: String, reg: SourceRegion) extends MMTAsset(name, reg) { + private lazy val longDescription = mmtplugin.asString(obj) + override def getLongString = longDescription def getScope = parent.parent match { case cp: ContentPath => Some(cp.module) case _ => None } + + /** tries to infer the type of this asset (may throw exceptions) */ + def inferType: Option[Term] = { + obj match { + case t: Term => + val thy = getScope.getOrElse(return None) + checking.Solver.infer(mmtplugin.controller, Context(thy) ++ context, t, None) + case _ => None + } + } } class MMTNotAsset(owner: ContentPath, label: String, not: TextNotation, reg: SourceRegion) extends MMTAsset(label, reg) { + setLongDescription(not.toText) def getScope = Some(owner.module) -} \ No newline at end of file +} + +/** a dummy asset for structuring the tree */ +class MMTAuxAsset(label: String) extends enhanced.SourceAsset(label, -1, MyPosition(-1)) diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/CompileActions.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/CompileActions.scala index b41f441306..e614556167 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/CompileActions.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/CompileActions.scala @@ -1,63 +1,64 @@ -package info.kwarc.mmt.jedit - -import info.kwarc.mmt.api._ -import info.kwarc.mmt.api.archives.source -import info.kwarc.mmt.api.utils._ -import org.gjt.sp.jedit._ - -/** This class collects all build-related functionality to be triggered by GUI button, jedit actions, etc.. */ -class BuildActions(mmtplugin: MMTPlugin) { - private val errorSource = mmtplugin.errorSource - private val controller = mmtplugin.controller - private def log(msg: String) {controller.report("jedit-compile", msg)} - - /** builds a file or directory */ - def build(f: String) { - val file = File(f) - val errorCont = new ErrorListForwarder(errorSource, controller, file) - errorCont.reset - if (file.isFile) { - log("build file " + file) - try { - controller.build(file)(errorCont) - } catch { - case e: Error => errorCont(e) - } - } - } - - //TODO saving may trigger sidekick-parsing in which case parsing and building happen at the same time and likely confuse each other - private def saveAndBuild(view: View, buffer: Buffer) { - if (buffer.isDirty) { - buffer.save(view, null) - io.VFSManager.waitForRequests // wait until buffer is saved - } - build(buffer.getPath) } - - /** saves and builds the current file of the current view */ - def buildCurrent(view: View) { - val buffer = view.getBuffer - saveAndBuild(view, buffer) - } - /** saves and builds the open files in the current view */ - def buildOpen(view: View) { - val buffers = view.getBuffers - buffers.foreach {b => saveAndBuild(view, b)} - } - /** saves and build the file/folder currently selected in the the file browser */ - def buildSelected(view: View, brw: browser.VFSBrowser) { - val files = brw.getSelectedFiles - files foreach {vfsfile => - val file = vfsfile.getPath - // save if the file is open - if (vfsfile.getType != io.VFSFile.DIRECTORY) { - val buffer = jEdit.getBuffer(file) - if (buffer != null) { - buffer.save(view, null) - io.VFSManager.waitForRequests // wait until buffer is saved - } - } - build(file) - } - } -} \ No newline at end of file +package info.kwarc.mmt.jedit + +import info.kwarc.mmt.api._ +import info.kwarc.mmt.api.archives.source +import info.kwarc.mmt.api.utils._ +import org.gjt.sp.jedit._ + +/** This class collects all build-related functionality to be triggered by GUI button, jedit actions, etc.. */ +class BuildActions(mmtplugin: MMTPlugin) { + private val errorSource = mmtplugin.errorSource + private val controller = mmtplugin.controller + private def log(msg: String) {controller.report("jedit-compile", msg)} + + /** builds a file or directory */ + def build(f: String) { + val file = File(f) + val errorCont = new ErrorListForwarder(errorSource, controller, file) + errorCont.reset + if (file.isFile) { + log("build file " + file) + try { + controller.build(file)(errorCont) + } catch { + case e: Error => errorCont(e) + } + } + } + + //TODO saving may trigger sidekick-parsing in which case parsing and building happen at the same time and likely confuse each other + private def saveAndBuild(view: View, buffer: Buffer) { + if (buffer.isDirty) { + buffer.save(view, null) + io.VFSManager.waitForRequests // wait until buffer is saved + } + build(buffer.getPath) + } + + /** saves and builds the current file of the current view */ + def buildCurrent(view: View) { + val buffer = view.getBuffer + saveAndBuild(view, buffer) + } + /** saves and builds the open files in the current view */ + def buildOpen(view: View) { + val buffers = view.getBuffers + buffers.foreach {b => saveAndBuild(view, b)} + } + /** saves and build the file/folder currently selected in the the file browser */ + def buildSelected(view: View, brw: browser.VFSBrowser) { + val files = brw.getSelectedFiles + files foreach {vfsfile => + val file = vfsfile.getPath + // save if the file is open + if (vfsfile.getType != io.VFSFile.DIRECTORY) { + val buffer = jEdit.getBuffer(file) + if (buffer != null) { + buffer.save(view, null) + io.VFSManager.waitForRequests // wait until buffer is saved + } + } + build(file) + } + } +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Completion.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Completion.scala index ec6b33cddc..635fd05afc 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Completion.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Completion.scala @@ -20,7 +20,7 @@ import scala.collection.JavaConversions.seqAsJavaList /** * @param view the current jEdit view * @param controller the current MMT controller - * @param constants the MMT constants that are applicable here + * @param constants the MMT constants that are applicable here * @param text the partial identifier that is completed * @param items the list of completion labels that is displayed */ @@ -75,15 +75,14 @@ class ProverCompletion(view : org.gjt.sp.jedit.View, controller: Controller, reg val ta = view.getEditPane.getTextArea val begin = region.start.offset val beginChar = ta.getText(begin,1) - ta.setSelection(new Selection.Range(begin, region.end.offset+1)) // workaround for empty terms: selection includes US val correctEmptyTerm = begin == region.end.offset && parser.Reader.delims.contains(beginChar(0)) // insert new text - ta.setSelectedText(newText + (if (correctEmptyTerm) beginChar else "")) + EditActions.overwriteText(ta, begin, region.end.offset, newText + (if (correctEmptyTerm) beginChar else "")) // reparse the buffer (will happen in background) SideKickPlugin.parse(view, false) // find next hole in the inserted text and move the caret to it val nextHole = ta.getText(begin,newText.length).indexOf(beginChar) ta.setCaretPosition(if (nextHole != -1) begin+nextHole else begin) } -} \ No newline at end of file +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/EditOperations.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/EditOperations.scala new file mode 100644 index 0000000000..add041af16 --- /dev/null +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/EditOperations.scala @@ -0,0 +1,91 @@ +package info.kwarc.mmt.jedit + +import info.kwarc.mmt.api._ +import gui.Swing + +import org.gjt.sp.jedit._ +import textarea._ + +object EditActions { + /** replaces a part of the text, first and last are inclusive */ + def overwriteText(textArea: TextArea, first: Int, last: Int, withText: String) { + textArea.setSelection(new Selection.Range(first,last+1)) + textArea.setSelectedText(withText) + } +} + +/** collects functionality that changes the text in the buffer + * these functions should be bound to actions in actions.xml, which can then be bound to keystrokes etc. + */ +class EditActions(mmtplugin: MMTPlugin) { + def introduceHole(view: View) { + val editPane = view.getEditPane + val textArea = editPane.getTextArea + val buffer = editPane.getBuffer + val offset = textArea.getCaretPosition + if (buffer.getText(offset,1) != "_") + return + val as = MMTSideKick.getAssetAtOffset(view, offset).getOrElse(return) + as match { + case oa: MMTObjAsset => + val tp = oa.inferType.getOrElse(return) + val tm = checking.Hole(tp) + val tmS = mmtplugin.controller.presenter.asString(tm) + EditActions.overwriteText(textArea, offset, offset, tmS) + case _ => + } + } + + /** + * shows the normalization of the current asset (selection or cursor) + * @param replace if true, replace selected asset; otherwise, show popup + */ + def showNormalization(view: View, replace: Boolean) { + val (as,selected) = MMTSideKick.getCurrentAsset(view).getOrElse(return) + as match { + case oa: MMTObjAsset => + val obj = oa.obj + val objS = mmtplugin.controller.simplifier(obj, oa.context, true) + val str = mmtplugin.asString(objS) + val textArea = view.getTextArea + if (selected && replace) { + textArea.setSelectedText(str) + } else { + if (selected) { + textArea.setSelection(oa.toSelection) + } + new TextareaPopup(textArea, oa.region.start.offset, str) // to be closed by user clicking the button + } + case _ => + } + } +} + + +import javax.swing._ +import java.awt.{Color,FlowLayout} +/** pops up a small text window on top of a TextArea */ +class TextareaPopup(textArea: TextArea, offset: Int, text: String) extends JFrame() { + private val contentArea = new JTextArea() + private val closeButton = Swing.Button("X"){dispose} + def set(content: String) { + contentArea.setText(content) + pack() + } + def setLocationRelativeToOffset(deltax: Int, deltay: Int) { + val p = textArea.offsetToXY(offset) + SwingUtilities.convertPointToScreen(p, textArea.getPainter) + setLocation(p.getX.toInt + deltax, p.getY.toInt + deltay) + } + contentArea.setEditable(false) + contentArea.setBorder(new border.LineBorder(Color.BLACK, 1, false)) + closeButton.setSize(10,10) + setLayout(new FlowLayout()) + add(contentArea) + add(closeButton) + setAlwaysOnTop(true) + setUndecorated(true) + set(text) + setLocationRelativeToOffset(0,30) + setVisible(true) +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/ErrorForwarder.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/ErrorForwarder.scala index 7cb4dfccf8..b9c5d560ff 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/ErrorForwarder.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/ErrorForwarder.scala @@ -1,148 +1,152 @@ -package info.kwarc.mmt.jedit - -import errorlist._ -import info.kwarc.mmt.api._ -import archives.source -import frontend._ -import objects._ -import org.gjt.sp.jedit.jEdit -import parser._ -import utils.MyList._ -import utils._ - -/** customizes the default errors of the ErrorList plugin - * @param mainFile the file whose checking led to the error (may differ from the file that contains the error) - */ -class MMTError(val mainFile: File, es: ErrorSource, el: Int, sf: String, sl: Int, sc: Int, ec: Int, msg: String) - extends DefaultErrorSource.DefaultError(es, el, sf, sl, sc, ec, msg) - -/** customizes the default error source of the ErrorList plugin */ -class MMTErrorSource extends DefaultErrorSource("MMT") { - - /** like superclass but allows only [[MMTError]]s */ - override def addError(e: DefaultErrorSource.DefaultError) { - e match { - case e: MMTError => super.addError(e) - case _ => throw ImplementationError("illegal error") - } - } - - /** remove errors produced when checking this file */ - def removeFileErrors(file: File) { - val sets = errors.values.iterator - while (sets.hasNext) { - val set = sets.next - val es = set.iterator - var remove: List[MMTError] = Nil - while (es.hasNext) { - es.next match { - case e: MMTError => - if (e.mainFile == file) { - remove ::= e - } - case e => - // should be impossible - } - } - remove.foreach {e => - set.remove(e) - gui.Swing.invokeLater { - val msg = new ErrorSourceUpdate(this, ErrorSourceUpdate.ERROR_REMOVED, e) - org.gjt.sp.jedit.EditBus.send(msg) - } - } - } - } -} - -/** - * sends MMT errors directly to jEdit ErrorList - * @param file the source file, in which the errors are found - */ -class ErrorListForwarder(errorSource: MMTErrorSource, controller: Controller, mainFile: File) extends ErrorHandler { - /** - * remove all errors whose mainFile is src - */ - private var errors : Array[ErrorSource.Error] = Array() - override def reset { - errorSource.removeFileErrors(mainFile) - errors = Array() - super.reset - } - protected def addError(e: Error) : Unit = e match { - case s: SourceError => - //generated by parsers - val tp = if (s.level == Level.Warning) ErrorSource.WARNING else ErrorSource.ERROR - val reg = s.ref.region - val pos = reg.start - // We permit the case that errors are found in other files than the current one. So we compute the file path - val file = controller.backend.resolveLogical(s.ref.container) match { - case Some((a, p)) => (a / source / p).toString - case None => s.ref.container match { - case utils.FileURI(f) => f.toString - case u => u.toString - } - } - val error = try { - val (line,column) = if (pos.line == -1 || pos.column == -1) { - // unknown line/column: compute from offset - val buf = jEdit.getBuffer(mainFile.toString) //TODO does this actually find the buffer? - val l = buf.getLineOfOffset(pos.offset) - (l, pos.offset-buf.getLineStartOffset(l)) - } else - (pos.line,pos.column) - new MMTError(mainFile, errorSource, tp, file, line, column, column + reg.length, s.mainMessage) - } catch { - case t : Exception => - return addError(GeneralError("error while registering error in jedit (error locations invalid? " + s.ref + ")").setCausedBy(t)) - } - s.extraMessages foreach {m => error.addExtraMessage(m)} - errorSource.addError(error) - case e: Invalid => - //generated by checkers - var mainMessage = e.shortMsg - var extraMessages : List[String] = Nil - val causeOpt: Option[metadata.HasMetaData] = e match { - case e: InvalidObject => Some(e.obj) - case e: InvalidElement => Some(e.elem) - case e: InvalidUnit => - val steps = e.history.getSteps - extraMessages = steps.map(_.present(o => controller.presenter.asString(o))) - val declOpt = e.unit.component.map(p => controller.localLookup.get(p.parent)) - // WFJudgement must exist because we always start with it - // find first WFJudgement whose region is within the failed checking unit - // but maybe lastWFJ.wfo has lost its region through simplification? - declOpt flatMap {decl => - SourceRef.get(decl).flatMap {bigRef => - steps.mapFind { - case j: WFJudgement => - SourceRef.get(j.wfo) flatMap {smallRef => - if (bigRef contains smallRef) { - mainMessage += ": " + controller.presenter.asString(j.wfo) - Some(j.wfo) - } else - None - } - case _ => None - } - }.orElse(declOpt) - } - } - val ref = causeOpt.flatMap {cause => SourceRef.get(cause)}.getOrElse { - mainMessage = "error with unknown location: " + mainMessage - SourceRef(utils.FileURI(mainFile), SourceRegion(SourcePosition(0,0,0), SourcePosition(0,0,0))) - } - val reg = ref.region - val error = new MMTError(mainFile, errorSource, ErrorSource.ERROR, mainFile.toString, - reg.start.line, reg.start.column, reg.start.column + reg.length, mainMessage) - extraMessages foreach {m => error.addExtraMessage(m)} - errorSource.addError(error) - case e: Error => - // other errors, should not happen - val error = new MMTError(mainFile, - errorSource, ErrorSource.ERROR, mainFile.toString, 0, 0, 1, "error with unknown location: " + e.getMessage - ) - e.toStringLong.split("\\n").foreach {m => error.addExtraMessage(m)} - errorSource.addError(error) - } -} +package info.kwarc.mmt.jedit + +import errorlist._ +import info.kwarc.mmt.api._ +import archives.source +import frontend._ +import objects._ +import org.gjt.sp.jedit.jEdit +import parser._ +import utils.MyList._ +import utils._ + +/** customizes the default errors of the ErrorList plugin + * @param mainFile the file whose checking led to the error (may differ from the file that contains the error) + */ +class MMTError(val mainFile: File, es: ErrorSource, el: Level.Level, sf: String, sl: Int, sc: Int, ec: Int, msg: String, extraMsg: List[String]) + extends DefaultErrorSource.DefaultError(es, MMTError.mmtLevelTojEditLevel(el), sf, sl, sc, ec, msg) { + extraMsg foreach {m => addExtraMessage(m)} +} + +object MMTError { + def apply(mainFile: File, es: ErrorSource, e: Error, sf: String, reg: SourceRegion, msg: String, extraMsg: List[String]) = { + val pos = reg.start + try { + val (line,column) = if (pos.line == -1 || pos.column == -1) { + // unknown line/column: compute from offset + val buf = jEdit.getBuffer(mainFile.toString) //TODO does this actually find the buffer? + val l = buf.getLineOfOffset(pos.offset) + (l, pos.offset-buf.getLineStartOffset(l)) + } else + (pos.line,pos.column) + new MMTError(mainFile, es, e.level, sf, line, column, column + reg.length, msg, extraMsg) + } catch { + case t: Exception => + val tMsg = "error while creating error (illegal region?: " + reg + ")" + new MMTError(mainFile, es, e.level, sf, 0, 0, 1, tMsg, msg :: extraMsg) + } + } + def mmtLevelTojEditLevel(mmtLevel: Level.Level): Int = if (mmtLevel >= Level.Error) ErrorSource.ERROR else ErrorSource.WARNING +} + +/** customizes the default error source of the ErrorList plugin */ +class MMTErrorSource extends DefaultErrorSource("MMT") { + + /** like superclass but allows only [[MMTError]]s */ + override def addError(e: DefaultErrorSource.DefaultError) { + e match { + case e: MMTError => super.addError(e) + case _ => throw ImplementationError("illegal error") + } + } + + /** remove errors produced when checking this file */ + def removeFileErrors(file: File) { + val sets = errors.values.iterator + while (sets.hasNext) { + val set = sets.next + val es = set.iterator + var remove: List[MMTError] = Nil + while (es.hasNext) { + es.next match { + case e: MMTError => + if (e.mainFile == file) { + remove ::= e + } + case e => + // should be impossible + } + } + remove.foreach {e => + set.remove(e) + gui.Swing.invokeLater { + val msg = new ErrorSourceUpdate(this, ErrorSourceUpdate.ERROR_REMOVED, e) + org.gjt.sp.jedit.EditBus.send(msg) + } + } + } + } +} + +/** + * sends MMT errors directly to jEdit ErrorList + * @param file the source file, in which the errors are found + */ +class ErrorListForwarder(errorSource: MMTErrorSource, controller: Controller, mainFile: File) extends ErrorHandler { + /** + * remove all errors whose mainFile is src + */ + private var errors : Array[ErrorSource.Error] = Array() + override def reset { + errorSource.removeFileErrors(mainFile) + errors = Array() + super.reset + } + protected def addError(e: Error) : Unit = e match { + case s: SourceError => + //generated by parsers + // We permit the case that errors are found in other files than the current one. So we compute the file path + val file = controller.backend.resolveLogical(s.ref.container) match { + case Some((a, p)) => (a / source / p).toString + case None => s.ref.container match { + case utils.FileURI(f) => f.toString + case u => u.toString + } + } + val error = MMTError(mainFile, errorSource, s, file, s.ref.region, s.mainMessage, s.extraMessages) + errorSource.addError(error) + case e: Invalid => + //generated by checkers + var mainMessage = e.shortMsg + var extraMessages : List[String] = e.extraMessage.split("\n").toList + val causeOpt: Option[metadata.HasMetaData] = e match { + case e: InvalidObject => Some(e.obj) + case e: InvalidElement => Some(e.elem) + case e: InvalidUnit => + val steps = e.history.getSteps + extraMessages :::= steps.map(_.present(o => controller.presenter.asString(o))) + val declOpt = e.unit.component.map(p => controller.localLookup.get(p.parent)) + // WFJudgement must exist because we always start with it + // find first WFJudgement whose region is within the failed checking unit + declOpt flatMap {decl => + SourceRef.get(decl).flatMap {bigRef => + steps.mapFind {s => + s.removeWrappers match { + case j: WFJudgement => + SourceRef.get(j.wfo) flatMap {smallRef => + if (bigRef contains smallRef) { + mainMessage += ": " + controller.presenter.asString(j.wfo) + Some(j.wfo) + } else + None + } + case _ => + None + } + } + }.orElse(declOpt) + } + } + val ref = causeOpt.flatMap {cause => SourceRef.get(cause)}.getOrElse { + mainMessage = "error with unknown location: " + mainMessage + SourceRef(utils.FileURI(mainFile), SourceRegion(SourcePosition(0,0,0), SourcePosition(0,0,0))) + } + val error = MMTError(mainFile, errorSource, e, mainFile.toString, ref.region, mainMessage, extraMessages) + errorSource.addError(error) + case e: Error => + // other errors, should not happen + val msg = "error with unknown location: " + e.getMessage + val error = new MMTError(mainFile, errorSource, e.level, mainFile.toString, 0, 0, 1, msg, stringToList(e.toStringLong,"\n")) + errorSource.addError(error) + } +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Hider.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Hider.scala deleted file mode 100644 index 549c335d28..0000000000 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Hider.scala +++ /dev/null @@ -1,47 +0,0 @@ -/* nice idea but did not work out well in practice -package info.kwarc.mmt.jedit - -import org.gjt.sp.jedit._ -import textarea._ - -/** implements hiding-related functions */ -object Hider { - val hideStart = "%{HIDE" - val hideEnd = "}%" - val showStart = "%{SHOW" - val showEnd = "}%" - /** show all hidable parts in the current selection */ - def show(ta: TextArea) { - if (ta.getSelectionCount() != 1) return - val sel = ta.getSelectedText() - val selChanged = sel.replace("{HIDE","{SHOW") - ta.setSelectedText(selChanged) - } - /** hide all hidable parts in the current selection */ - def hide(ta: TextArea) { - if (ta.getSelectionCount() != 1) return - val sel = ta.getSelectedText() - val selChanged = sel.replace("{SHOW","{HIDE") - ta.setSelectedText(selChanged) - } - /** toggle all hidable parts in the current selection */ - def hideshow(ta: TextArea) { - if (ta.getSelectionCount() != 1) return - var sel = ta.getSelectedText() - sel = sel.replace("{SHOW","{HIXXXDE").replace("{HIDE", "{SHOW").replace("{HIXXXDE", "{HIDE") - ta.setSelectedText(sel) - } - /** makes the current selection hidable and hides it */ - def makeHidable(ta: TextArea) { - if (ta.getSelectionCount() != 1) return - val sel = ta.getSelectedText() - val selChanged = hideStart + sel + hideEnd - ta.setSelectedText(selChanged) - } - /** hides the hideable part that the caret is in */ - def hideCurrent(ta: TextArea) { - ta.selectBlock - hide(ta) - } -} -*/ \ No newline at end of file diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Inserter.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Inserter.scala index 78f4cdd4ca..927fe6d657 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Inserter.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/Inserter.scala @@ -1,29 +1,29 @@ -package info.kwarc.mmt.jedit - -import info.kwarc.mmt.api.parser._ - -import org.gjt.sp.jedit._ -import textarea._ - -object Inserter { - private def getChar(d: Reader.MMTDelim) = { - val chars = d.chars - val c = if (MMTOptions.lowAsciiDelims.get.getOrElse(false)) chars.last else chars.head - c.toChar.toString - } - - private def insert(ta: TextArea, ifmmt: String, ifother: String) { - val insert = if (ta.getBuffer.getMode.getName == "mmt") ifmmt else ifother - ta.replaceSelection(insert) - } - def insertUSorTab(ta: TextArea) { - val offset = ta.getCaretPosition - insert(ta, getChar(Reader.US), "\t") - } - def insertRSReturn(ta: TextArea) { - insert(ta, getChar(Reader.RS) + "\n", "\n") - } - def insertGSReturn(ta: TextArea) { - insert(ta, getChar(Reader.GS) + "\n", "\n") - } -} +package info.kwarc.mmt.jedit + +import info.kwarc.mmt.api.parser._ + +import org.gjt.sp.jedit._ +import textarea._ + +object Inserter { + private def getChar(d: Reader.MMTDelim) = { + val chars = d.chars + val c = if (MMTOptions.lowAsciiDelims.get.getOrElse(false)) chars.last else chars.head + c.toChar.toString + } + + private def insert(ta: TextArea, ifmmt: String, ifother: String) { + val insert = if (ta.getBuffer.getMode.getName == "mmt") ifmmt else ifother + ta.replaceSelection(insert) + } + def insertUSorTab(ta: TextArea) { + val offset = ta.getCaretPosition + insert(ta, getChar(Reader.US), "\t") + } + def insertRSReturn(ta: TextArea) { + insert(ta, getChar(Reader.RS) + "\n", "\n") + } + def insertGSReturn(ta: TextArea) { + insert(ta, getChar(Reader.GS) + "\n", "\n") + } +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTBufferListener.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTBufferListener.scala deleted file mode 100644 index d008e63133..0000000000 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTBufferListener.scala +++ /dev/null @@ -1,16 +0,0 @@ -/* -package info.kwarc.mmt.jedit -import info.kwarc.mmt.api._ -import frontend._ -import org.gjt.sp.jedit._ -import buffer._ - -class MMTBufferListener(controller: Controller) extends BufferAdapter { - override def contentInserted(bufer: JEditBuffer, startLine: Int, offset: Int, numLines: Int, length: Int) { - - } - override def contentRemoved(bufer: JEditBuffer, startLine: Int, offset: Int, numLines: Int, length: Int) { - - } -} -*/ \ No newline at end of file diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTConsole.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTConsole.scala index 6a4dc50c54..63855683ee 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTConsole.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTConsole.scala @@ -1,45 +1,46 @@ -package info.kwarc.mmt.jedit -import org.gjt.sp.jedit._ -import console._ -import info.kwarc.mmt.api.frontend.{Action, ReportHandler} - -class OutputAsReport(output: Output) extends ReportHandler("jEdit console") { - def apply(ind: Int, caller: => String, group : String, msgParts : List[String]) { - msgParts.foreach {msg => output.print(null, indentString(ind) + group + ": " + msg)} // null for default color - } -} - -class MMTConsole extends console.Shell("mmt") { - val mmt : MMTPlugin = jEdit.getPlugin("info.kwarc.mmt.jedit.MMTPlugin", true).asInstanceOf[MMTPlugin] - val controller = mmt.controller - //This method is invoked by the console when the user selects the shell in question. It should print a short informational message, outlining the main capabilities of the shell. - override def printInfoMessage (output: Output) { - output.print(null, "This is the MMT Shell") - } - //If your shell executes commands in a separate thread, this method should stop the currently running thread, if any. - override def stop (console: Console) {} - private var success : Option[Boolean] = Some(true) - - //This method should block until the currently running command has completed, and return true if the command executed successfully, false otherwise. If no command is currently running, it should return the status of the most recently run command. - override def waitFor(console: Console) : Boolean = true - - override def getCompletions(console: Console, command: String): Shell.CompletionInfo = new Shell.CompletionInfo { - offset = 0 - completions = Action.completeAct(command).toArray - } - - def execute(console: Console, input: String, output: Output, error: Output, command: String) { - val han = new OutputAsReport(output) - controller.report.addHandler(han) - success = None - try { - controller.handleLine(command) - } catch { - case e: Exception => controller.report("error", e.getMessage) - } finally { - controller.report.removeHandler(han.id) - success = Some(true) - output.commandDone() - } - } -} +package info.kwarc.mmt.jedit +import org.gjt.sp.jedit._ +import console._ +import info.kwarc.mmt.api.frontend.ReportHandler +import info.kwarc.mmt.api.frontend.actions.Action + +class OutputAsReport(output: Output) extends ReportHandler("jEdit console") { + def apply(ind: Int, caller: => String, group : String, msgParts : List[String]) { + msgParts.foreach {msg => output.print(null, indentString(ind) + group + ": " + msg)} // null for default color + } +} + +class MMTConsole extends console.Shell("mmt") { + val mmt : MMTPlugin = jEdit.getPlugin("info.kwarc.mmt.jedit.MMTPlugin", true).asInstanceOf[MMTPlugin] + val controller = mmt.controller + //This method is invoked by the console when the user selects the shell in question. It should print a short informational message, outlining the main capabilities of the shell. + override def printInfoMessage (output: Output) { + output.print(null, "This is the MMT Shell") + } + //If your shell executes commands in a separate thread, this method should stop the currently running thread, if any. + override def stop (console: Console) {} + private var success : Option[Boolean] = Some(true) + + //This method should block until the currently running command has completed, and return true if the command executed successfully, false otherwise. If no command is currently running, it should return the status of the most recently run command. + override def waitFor(console: Console) : Boolean = true + + override def getCompletions(console: Console, command: String): Shell.CompletionInfo = new Shell.CompletionInfo { + offset = 0 + completions = Action.completeAct(command).toArray + } + + def execute(console: Console, input: String, output: Output, error: Output, command: String) { + val han = new OutputAsReport(output) + controller.report.addHandler(han) + success = None + try { + controller.handleLine(command) + } catch { + case e: Exception => controller.report("error", e.getMessage) + } finally { + controller.report.removeHandler(han.id) + success = Some(true) + output.commandDone() + } + } +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTDockable.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTDockable.scala index 81647cba64..bd1649dc69 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTDockable.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTDockable.scala @@ -1,19 +1,19 @@ -package info.kwarc.mmt.jedit - -import java.awt.GridLayout - -import info.kwarc.mmt.api._ -import gui._ -import org.gjt.sp.jedit._ -import javax.swing._ - -class MMTDockable(view: View, position: String) extends JPanel { - val mmt : MMTPlugin = jEdit.getPlugin("info.kwarc.mmt.jedit.MMTPlugin", true).asInstanceOf[MMTPlugin] - val controller = mmt.controller - def init { - setLayout(new GridLayout(1,1)) - val gui = new JScrollPane(new GUIPanel(controller)) - add(gui) - } - init -} +package info.kwarc.mmt.jedit + +import java.awt.GridLayout + +import info.kwarc.mmt.api._ +import gui._ +import org.gjt.sp.jedit._ +import javax.swing._ + +class MMTDockable(view: View, position: String) extends JPanel { + val mmt : MMTPlugin = jEdit.getPlugin("info.kwarc.mmt.jedit.MMTPlugin", true).asInstanceOf[MMTPlugin] + val controller = mmt.controller + def init { + setLayout(new GridLayout(1,1)) + val gui = new JScrollPane(new GUIPanel(controller)) + add(gui) + } + init +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTHyperLinkSource.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTHyperLinkSource.scala index 86b9d807db..0f83295cd3 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTHyperLinkSource.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTHyperLinkSource.scala @@ -1,96 +1,96 @@ -package info.kwarc.mmt.jedit - -import gatchan.jedit.hyperlinks._ -import info.kwarc.mmt.api._ -import info.kwarc.mmt.api.archives.source -import info.kwarc.mmt.api.parser._ -import info.kwarc.mmt.api.utils._ -import org.gjt.sp.jedit._ -import sidekick._ - -//TODO it should be enough to compute the SourceRef at click time -/** implements the action for clicking on a hyperlink provided by [[MMTHyperlinkSource]] */ -class MMTHyperlink(start: Int, end: Int, startLine: Int, path: Path, ref: Option[SourceRef]) - extends AbstractHyperlink(start, end, startLine, path.toPath) { - def click(view: View) { - ref foreach {r => MMTHyperlink.navigateTo(view, r)} - } -} - -object MMTHyperlink { - /** extracts physical source references from a structural element */ - def elemToSourceRef(controller: frontend.Controller, elem: StructuralElement) : Option[SourceRef] = { - val ref = SourceRef.get(elem) - // we may have a ref now, but it's only useful if it's a file:URI - ref flatMap {r => - val c = r.container - if (c.scheme == Some("file")) Some(r) - else { - //resolve logical document id in an archive - controller.backend.resolveLogical(c) map { - case (archive, path) => r.copy(container = FileURI(archive / source / path)) - } - } - } - } - /** navigates to a SourceRef in a jedit view */ - def navigateTo(view: View, ref: SourceRef) { - ref match { - case SourceRef(FileURI(file), region) => - var buffer = jEdit.getBuffer(file.toString) - if (buffer == null) { - buffer = jEdit.openFile(view, file.toString) - io.VFSManager.waitForRequests // wait until buffer is open - } - val editPane = view.goToBuffer(buffer) - editPane.getTextArea.moveCaretPosition(region.start.offset) - case _ => - } - } -} - -/** uses [[SourceRef]]s to provide hyperlinks in MMT documents */ -class MMTHyperlinkSource extends HyperlinkSource { - val mmt : MMTPlugin = jEdit.getPlugin("info.kwarc.mmt.jedit.MMTPlugin", true).asInstanceOf[MMTPlugin] - val controller = mmt.controller - private def log(msg : => String) {controller.report("jedit-link", msg)} - private var currentLink : Hyperlink = null - def getHyperlink(buffer: Buffer, caretPosition: Int) : Hyperlink = try { - // return a previously found link if it is still applicable - if (currentLink != null && currentLink.getStartOffset() <= caretPosition && currentLink.getEndOffset() >= caretPosition) - return currentLink - val asset = SideKickParsedData.getParsedData(jEdit.getActiveView).getAssetAtOffset(caretPosition) match { - case a: MMTAsset => a - case _ => return null - } - currentLink = MMTPlugin.getCurrentID(buffer, caretPosition) match { - case None => null - case Some((line, begin, end, id)) => - log(id) - val elemOpt: Option[StructuralElement] = asset match { - case a: MMTObjAsset => - a.obj match { - case t: objects.Term => - a.pragmatic.head flatMap {h => - controller.globalLookup.getO(h) - } - case _ => None - } - case a: MMTURIAsset => - controller.globalLookup.getO(a.path) - case _ => None - //asset.getScope flatMap {home => libraries.Names.resolve(home, id)(controller.localLookup)} - } - val linkOpt = elemOpt map {elem => - val ref = MMTHyperlink.elemToSourceRef(controller,elem) - log(ref.map(_.toString).getOrElse("no file reference")) - new MMTHyperlink(begin, end, line, elem.path, ref) - } - linkOpt.getOrElse(null) - } - currentLink - } catch { - case e: Error => controller.report(e); null - case e: java.lang.Exception => log(e.getMessage); null - } -} +package info.kwarc.mmt.jedit + +import gatchan.jedit.hyperlinks._ +import info.kwarc.mmt.api._ +import info.kwarc.mmt.api.archives.source +import info.kwarc.mmt.api.parser._ +import info.kwarc.mmt.api.utils._ +import org.gjt.sp.jedit._ +import sidekick._ + +//TODO it should be enough to compute the SourceRef at click time +/** implements the action for clicking on a hyperlink provided by [[MMTHyperlinkSource]] */ +class MMTHyperlink(start: Int, end: Int, startLine: Int, path: Path, ref: Option[SourceRef]) + extends AbstractHyperlink(start, end, startLine, path.toPath) { + def click(view: View) { + ref foreach {r => MMTHyperlink.navigateTo(view, r)} + } +} + +object MMTHyperlink { + /** extracts physical source references from a structural element */ + def elemToSourceRef(controller: frontend.Controller, elem: StructuralElement) : Option[SourceRef] = { + val ref = SourceRef.get(elem) + // we may have a ref now, but it's only useful if it's a file:URI + ref flatMap {r => + val c = r.container + if (c.scheme == Some("file")) Some(r) + else { + //resolve logical document id in an archive + controller.backend.resolveLogical(c) map { + case (archive, path) => r.copy(container = FileURI(archive / source / path)) + } + } + } + } + /** navigates to a SourceRef in a jedit view */ + def navigateTo(view: View, ref: SourceRef) { + ref match { + case SourceRef(FileURI(file), region) => + var buffer = jEdit.getBuffer(file.toString) + if (buffer == null) { + buffer = jEdit.openFile(view, file.toString) + io.VFSManager.waitForRequests // wait until buffer is open + } + val editPane = view.goToBuffer(buffer) + editPane.getTextArea.moveCaretPosition(region.start.offset) + case _ => + } + } +} + +/** uses [[SourceRef]]s to provide hyperlinks in MMT documents */ +class MMTHyperlinkSource extends HyperlinkSource { + val mmt : MMTPlugin = jEdit.getPlugin("info.kwarc.mmt.jedit.MMTPlugin", true).asInstanceOf[MMTPlugin] + val controller = mmt.controller + private def log(msg : => String) {controller.report("jedit-link", msg)} + private var currentLink : Hyperlink = null + def getHyperlink(buffer: Buffer, caretPosition: Int) : Hyperlink = try { + // return a previously found link if it is still applicable + if (currentLink != null && currentLink.getStartOffset() <= caretPosition && currentLink.getEndOffset() >= caretPosition) + return currentLink + val asset = SideKickParsedData.getParsedData(jEdit.getActiveView).getAssetAtOffset(caretPosition) match { + case a: MMTAsset => a + case _ => return null + } + currentLink = MMTPlugin.getCurrentID(buffer, caretPosition) match { + case None => null + case Some((line, begin, end, id)) => + log(id) + val elemOpt: Option[StructuralElement] = asset match { + case a: MMTObjAsset => + a.obj match { + case t: objects.Term => + a.pragmatic.head flatMap {h => + controller.globalLookup.getO(h) + } + case _ => None + } + case a: MMTURIAsset => + controller.globalLookup.getO(a.path) + case _ => None + //asset.getScope flatMap {home => libraries.Names.resolve(home, id)(controller.localLookup)} + } + val linkOpt = elemOpt map {elem => + val ref = MMTHyperlink.elemToSourceRef(controller,elem) + log(ref.map(_.toString).getOrElse("no file reference")) + new MMTHyperlink(begin, end, line, elem.path, ref) + } + linkOpt.getOrElse(null) + } + currentLink + } catch { + case e: Error => controller.report(e); null + case e: java.lang.Exception => log(e.getMessage); null + } +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTInterpreter.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTInterpreter.scala index 7d10b8163d..ef6f1e3d59 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTInterpreter.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTInterpreter.scala @@ -2,7 +2,8 @@ package info.kwarc.mmt.jedit import console._ import info.kwarc.mmt.api._ -import frontend.{MMTInterpolator, SetBase} +import frontend.MMTInterpolator +import frontend.actions.SetBase import objects._ import org.gjt.sp.jedit._ import org.gjt.sp.jedit.bufferset._ @@ -190,7 +191,7 @@ Non-commands are MMT code. val parser = controller.extman.get(classOf[Parser], "mmt").get val t = parser(pu)(ErrorThrower).toTerm //Type checking - val stack = Stack(Context(theory)) + val stack = Stack(Context(theory)) val solveout = checking.Solver.check(controller, stack, t) val (tR, tpR) = solveout match{ diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTOptions.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTOptions.scala index e39abf180c..ee5df802b8 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTOptions.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTOptions.scala @@ -1,106 +1,106 @@ -package info.kwarc.mmt.jedit - -import info.kwarc.mmt.api.utils._ -import org.gjt.sp.jedit._ - -/** interface to the jedit settings file and the options dialog */ -abstract class MMTOption[A] { - def toString(a: A): String = a.toString - - def fromString(s: String): A - - /** an identifier for this option (must be unique among the MMTOptions) */ - val key: String - val jeditKey = "info.kwarc.mmt.jedit.MMTPlugin." + key - - /** get the current setting from jedit */ - def get: Option[A] = { - val p = jEdit.getProperty(jeditKey) - if (p == null || p == "") - None - else - Some(fromString(p)) - } - - /** set the setting in jedit */ - def set(a: A) { - jEdit.setProperty(jeditKey, toString(a)) - } - - val label: String - val guiComponent: java.awt.Component - - def fromGUIComponent: A - - def toGUIComponent(a: A) - - /** add an interface component to the jedit plugin options pane */ - def init(op: AbstractOptionPane) { - get.foreach { a => toGUIComponent(a) } - op.addComponent(label, guiComponent) - } - - /** save the values of the interface component to the jedit settings */ - def save { - set(fromGUIComponent) - } -} - -/** an option that is displayed as a text field */ -abstract class TextOption[A] extends MMTOption[A] { - val guiComponent = new java.awt.TextField - - def fromGUIComponent = fromString(guiComponent.getText) - - def toGUIComponent(a: A) = guiComponent.setText(toString(a)) -} - -/** a string-valued option */ -class StringOption(val key: String, val label: String) extends TextOption[String] { - def fromString(s: String) = s -} - -/** a File-valued option */ -class FileOption(val key: String, val label: String) extends TextOption[File] { - def fromString(s: String) = new java.io.File(s) -} - -/** a Boolean-valued option */ -class BooleanOption(val key: String, val label: String) extends MMTOption[Boolean] { - def fromString(s: String) = s match { - case "true" => true - case "false" => false - } - - val guiComponent = new java.awt.Checkbox - - def fromGUIComponent = guiComponent.getState - - def toGUIComponent(b: Boolean) = guiComponent.setState(b) -} - -/** contains the various MMT options - * - * to add an option, just create it here and add it to the list of all options - */ -object MMTOptions { - val startup = new StringOption("startup", "custom startup msl file") - val config = new StringOption("config", "custom configuration file") - val archives = new StringOption("archives", "custom folder that contains archives") - val lowAsciiDelims = new BooleanOption("lowAsciiDelims", "use ASCII 28-31 as delimiters") - val semantichighlighting = new BooleanOption("SemanticHighlighting","Semantic highlighting (does not work yet)") - /** the list of all options */ - val all = List(startup, config, archives, lowAsciiDelims, semantichighlighting) -} - -/** the MMT plugin options pane using the options defined in the companion object */ -class MMTOptions extends AbstractOptionPane("info.kwarc.mmt.jedit.MMTPlugin") { - override def _init { - addSeparator("all paths are relative to MMT plugin home") - MMTOptions.all foreach { c => c.init(this) } - } - - override def _save { - MMTOptions.all foreach { c => c.save } - } -} \ No newline at end of file +package info.kwarc.mmt.jedit + +import info.kwarc.mmt.api.utils._ +import org.gjt.sp.jedit._ + +/** interface to the jedit settings file and the options dialog */ +abstract class MMTOption[A] { + def toString(a: A): String = a.toString + + def fromString(s: String): A + + /** an identifier for this option (must be unique among the MMTOptions) */ + val key: String + val jeditKey = "info.kwarc.mmt.jedit.MMTPlugin." + key + + /** get the current setting from jedit */ + def get: Option[A] = { + val p = jEdit.getProperty(jeditKey) + if (p == null || p == "") + None + else + Some(fromString(p)) + } + + /** set the setting in jedit */ + def set(a: A) { + jEdit.setProperty(jeditKey, toString(a)) + } + + val label: String + val guiComponent: java.awt.Component + + def fromGUIComponent: A + + def toGUIComponent(a: A) + + /** add an interface component to the jedit plugin options pane */ + def init(op: AbstractOptionPane) { + get.foreach { a => toGUIComponent(a) } + op.addComponent(label, guiComponent) + } + + /** save the values of the interface component to the jedit settings */ + def save { + set(fromGUIComponent) + } +} + +/** an option that is displayed as a text field */ +abstract class TextOption[A] extends MMTOption[A] { + val guiComponent = new java.awt.TextField + + def fromGUIComponent = fromString(guiComponent.getText) + + def toGUIComponent(a: A) = guiComponent.setText(toString(a)) +} + +/** a string-valued option */ +class StringOption(val key: String, val label: String) extends TextOption[String] { + def fromString(s: String) = s +} + +/** a File-valued option */ +class FileOption(val key: String, val label: String) extends TextOption[File] { + def fromString(s: String) = new java.io.File(s) +} + +/** a Boolean-valued option */ +class BooleanOption(val key: String, val label: String) extends MMTOption[Boolean] { + def fromString(s: String) = s match { + case "true" => true + case "false" => false + } + + val guiComponent = new java.awt.Checkbox + + def fromGUIComponent = guiComponent.getState + + def toGUIComponent(b: Boolean) = guiComponent.setState(b) +} + +/** contains the various MMT options + * + * to add an option, just create it here and add it to the list of all options + */ +object MMTOptions { + val startup = new StringOption("startup", "custom startup msl file") + val config = new StringOption("config", "custom configuration file") + val archives = new StringOption("archives", "custom folder that contains archives") + val lowAsciiDelims = new BooleanOption("lowAsciiDelims", "use ASCII 28-31 as delimiters") + val semantichighlighting = new BooleanOption("SemanticHighlighting","Semantic highlighting (does not work yet)") + /** the list of all options */ + val all = List(startup, config, archives, lowAsciiDelims, semantichighlighting) +} + +/** the MMT plugin options pane using the options defined in the companion object */ +class MMTOptions extends AbstractOptionPane("info.kwarc.mmt.jedit.MMTPlugin") { + override def _init { + addSeparator("all paths are relative to MMT plugin home") + MMTOptions.all foreach { c => c.init(this) } + } + + override def _save { + MMTOptions.all foreach { c => c.save } + } +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTPlugin.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTPlugin.scala index 655ef18ddc..d3df24c1b2 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTPlugin.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTPlugin.scala @@ -1,198 +1,203 @@ - package info.kwarc.mmt.jedit - -import info.kwarc.mmt.api._ -import info.kwarc.mmt.api.frontend._ -import info.kwarc.mmt.api.utils.File._ -import org.gjt.sp.jedit._ -import org.gjt.sp.jedit.msg._ -import org.gjt.sp.jedit.textarea._ -import javax.swing.SwingUtilities - -/** - * The main class of the MMTPlugin - * after initialization, it creates a Controller and executes home/startup.mmt - * logging information is sent to home/mmtplugin.log - * the home directory is obtained from jEdit, e.g., settings/plugins/info.kwarc.mmt.jedit.MMTPlugin - */ -class MMTPlugin extends EBPlugin with Logger { - val controller = new Controller - val report = controller.report - val logPrefix = "jedit" - val errorSource = new MMTErrorSource - - val buildActions = new BuildActions(this) - - /** implements onNavigate hook in terms of the methods of MMTHyperlink */ - val mmtListener = new ChangeListener { - override def onNavigate(p: Path) { - log("navigating to " + p) - val ref = controller.getO(p) flatMap { - e => MMTHyperlink.elemToSourceRef(controller, e) - } - ref foreach {r => - val view = jEdit.getActiveView - MMTHyperlink.navigateTo(view, r) - } - } - } - - /** called by jEdit when plugin is loaded */ - override def start { - val home = getPluginHome - home.mkdirs - controller.setHome(home) - - val startup = MMTOptions.startup.get.getOrElse("startup.msl") - val file = home resolve startup - if (file.exists) - controller.execFileAction(file, None) - - val conf = MMTOptions.config.get.getOrElse("mmtrc") - val confFile = home resolve conf - if (confFile.exists) - controller.loadConfig(MMTConfig.parse(confFile), false) - - errorlist.ErrorSource.registerErrorSource(errorSource) - val archives = MMTOptions.archives.get orElse - controller.getOAF.map(_.root.toString) getOrElse "mars" - controller.addArchive(home resolve archives) - // status bar is not actually available yet at this point - controller.report.addHandler(StatusBarLogger) - controller.extman.addExtension(mmtListener) - jEdit.getViews foreach customizeView - // make tooltips stay longer - javax.swing.ToolTipManager.sharedInstance().setDismissDelay(100000) - } - /** called by jEdit when plugin is unloaded */ - override def stop { - controller.cleanup - errorlist.ErrorSource.unregisterErrorSource(errorSource) - jEdit.getViews foreach clearMMTToolBar - } - - override def handleMessage(message: EBMessage) { - message match { - //add MMTTextAreaExtension to every newly-created TextArea - case epu: EditPaneUpdate => - epu.getWhat match { - case EditPaneUpdate.CREATED => - log("handling " + epu.paramString) - val editPane = epu.getSource.asInstanceOf[EditPane] - customizeEditPane(editPane) - case _ => - } - case vup: ViewUpdate => - val view = vup.getView - vup.getWhat match { - case ViewUpdate.CREATED => - log("handling " + vup.paramString) - customizeView(view) - case ViewUpdate.CLOSED => - log("handling " + vup.paramString) - clearMMTToolBar(view) - case _ => - } - case _ => - } - } - - /** helper function that creates a thread and executes it */ - def invokeLater(code: => Unit) { - SwingUtilities.invokeLater( - new Runnable() { - def run() { - code - } - } - ) - } - - private def customizeView(view: View) { - view.getEditPanes foreach customizeEditPane - addMMTToolBar(view) - } - private def customizeEditPane(editPane: EditPane) { - val ta = editPane.getTextArea - val painter = ta.getPainter - if (!painter.getExtensions.exists(_.isInstanceOf[MMTTextAreaExtension])) { - val taExt = new MMTTextAreaExtension(controller, editPane) - painter.addExtension(TextAreaPainter.TEXT_LAYER, taExt) - } - //val sc = new StyleChanger(editPane, "mmt") - //painter.addExtension(TextAreaPainter.DEFAULT_LAYER, sc) - val ma = new MMTMouseAdapter(editPane) - painter.addMouseListener(ma) - - /* old code used for cleaning up - seems unnecessary - painter.putClientProperty(taKey, taExt) - case EditPaneUpdate.DESTROYED => - log("handling " + epu.paramString) - val taExt = painter.getClientProperty(taKey).asInstanceOf[TextAreaExtension] - if (taExt != null) { - painter.removeExtension(taExt) - painter.putClientProperty(taKey, null) - }*/ - } - - /** adds MMT toolbar */ - def addMMTToolBar(view: View) { - invokeLater { - clearMMTToolBar(view) - val viewToolBar = view.getToolBar - if (viewToolBar != null) { - log("adding toolbar...") - val newbar = new MMTToolBar(this) - viewToolBar.add(newbar) - } - } - } - /** removes MMT toolbar */ - def clearMMTToolBar(view: View) { - val viewToolBar = view.getToolBar - if (viewToolBar != null) { - log("Number of components of this view: " + viewToolBar.getComponentCount.toString) - viewToolBar.getComponents foreach {comp => - if(comp.isInstanceOf[MMTToolBar]) { - log("removing tool bar") - viewToolBar.remove(comp) - } - } - } - } -} - -object MMTPlugin { - def isIDChar(c: Char) = (! Character.isWhitespace(c)) && "()[]{}:.".forall(_ != c) - /** finds the id at a certain offset in a buffer - * @param buffer a buffer - * @param index offset in the buffer - * @return the id at the offset, if any, as (line,beginOffsetInBuffer,endOffsetInBuffer,id) - */ - def getCurrentID(buffer: Buffer, index: Int) : Option[(Int,Int,Int,String)] = { - val line = buffer.getLineOfOffset(index) - val lineStart = buffer.getLineStartOffset(line) - val lineLength = buffer.getLineLength(line) - if (lineLength == 0) - return None - var offset = index - lineStart - val lineText = buffer.getLineText(line) - if (offset == lineLength) - offset = offset - 1 - if (! isIDChar(lineText(offset))) - return None - var left = offset // first character of id - while (left > 0 && isIDChar(lineText(left - 1))) {left = left - 1} - var right = offset // last character of id - while (right < lineLength - 1 && isIDChar(lineText(right + 1))) {right = right + 1} - Some((line, lineStart + left, lineStart + right + 1, lineText.substring(left, right + 1))) - } -} - -object StatusBarLogger extends ReportHandler("jEdit") { - def apply(ind: Int, caller: => String, group: String, msg: List[String]) { - val v = jEdit.getActiveView - if (v != null) { - v.getStatus.setMessage("MMT " + group + ": " + msg.headOption.getOrElse("")) - } - } -} + package info.kwarc.mmt.jedit + +import info.kwarc.mmt.api._ +import info.kwarc.mmt.api.frontend._ +import info.kwarc.mmt.api.utils.File._ +import org.gjt.sp.jedit._ +import org.gjt.sp.jedit.msg._ +import org.gjt.sp.jedit.textarea._ +import javax.swing.SwingUtilities + +/** + * The main class of the MMTPlugin + * after initialization, it creates a Controller and executes home/startup.mmt + * logging information is sent to home/mmtplugin.log + * the home directory is obtained from jEdit, e.g., settings/plugins/info.kwarc.mmt.jedit.MMTPlugin + */ +class MMTPlugin extends EBPlugin with Logger { + val controller = new Controller + val report = controller.report + val logPrefix = "jedit" + val errorSource = new MMTErrorSource + + /** these are not used in the code, but called by actions in actions.xml */ + val buildActions = new BuildActions(this) + val editActions = new EditActions(this) + + /** convenience */ + def asString(o: objects.Obj) = controller.presenter.asString(o) + + /** implements onNavigate hook in terms of the methods of MMTHyperlink */ + val mmtListener = new ChangeListener { + override def onNavigate(p: Path) { + log("navigating to " + p) + val ref = controller.getO(p) flatMap { + e => MMTHyperlink.elemToSourceRef(controller, e) + } + ref foreach {r => + val view = jEdit.getActiveView + MMTHyperlink.navigateTo(view, r) + } + } + } + + /** called by jEdit when plugin is loaded */ + override def start { + val home = getPluginHome + home.mkdirs + controller.setHome(home) + + val startup = MMTOptions.startup.get.getOrElse("startup.msl") + val file = home resolve startup + if (file.exists) + controller.runMSLFile(file, None) + + val conf = MMTOptions.config.get.getOrElse("mmtrc") + val confFile = home resolve conf + if (confFile.exists) + controller.loadConfig(MMTConfig.parse(confFile), false) + + errorlist.ErrorSource.registerErrorSource(errorSource) + val archives = MMTOptions.archives.get orElse + controller.getMathHub.map(_.local.toString) getOrElse "mars" + controller.addArchive(home resolve archives) + // status bar is not actually available yet at this point + controller.report.addHandler(StatusBarLogger) + controller.extman.addExtension(mmtListener) + jEdit.getViews foreach customizeView + // make tooltips stay longer + javax.swing.ToolTipManager.sharedInstance().setDismissDelay(100000) + } + /** called by jEdit when plugin is unloaded */ + override def stop { + controller.cleanup + errorlist.ErrorSource.unregisterErrorSource(errorSource) + jEdit.getViews foreach clearMMTToolBar + } + + override def handleMessage(message: EBMessage) { + message match { + //add MMTTextAreaExtension to every newly-created TextArea + case epu: EditPaneUpdate => + epu.getWhat match { + case EditPaneUpdate.CREATED => + log("handling " + epu.paramString) + val editPane = epu.getSource.asInstanceOf[EditPane] + customizeEditPane(editPane) + case _ => + } + case vup: ViewUpdate => + val view = vup.getView + vup.getWhat match { + case ViewUpdate.CREATED => + log("handling " + vup.paramString) + customizeView(view) + case ViewUpdate.CLOSED => + log("handling " + vup.paramString) + clearMMTToolBar(view) + case _ => + } + case _ => + } + } + + /** helper function that creates a thread and executes it */ + def invokeLater(code: => Unit) { + SwingUtilities.invokeLater( + new Runnable() { + def run() { + code + } + } + ) + } + + private def customizeView(view: View) { + view.getEditPanes foreach customizeEditPane + addMMTToolBar(view) + } + private def customizeEditPane(editPane: EditPane) { + val ta = editPane.getTextArea + val painter = ta.getPainter + if (!painter.getExtensions.exists(_.isInstanceOf[MMTTextAreaExtension])) { + val taExt = new MMTTextAreaExtension(controller, editPane) + val tooltipExt = new MMTToolTips(controller, editPane) + painter.addExtension(TextAreaPainter.TEXT_LAYER, taExt) + painter.addExtension(TextAreaPainter.BELOW_MOST_EXTENSIONS_LAYER, tooltipExt) // jedit tries lower layers first when looking for a tooltip; we must be below error list + } + val ma = new MMTMouseAdapter(editPane) + painter.addMouseListener(ma) + + /* old code used for cleaning up - seems unnecessary + painter.putClientProperty(taKey, taExt) + case EditPaneUpdate.DESTROYED => + log("handling " + epu.paramString) + val taExt = painter.getClientProperty(taKey).asInstanceOf[TextAreaExtension] + if (taExt != null) { + painter.removeExtension(taExt) + painter.putClientProperty(taKey, null) + }*/ + } + + /** adds MMT toolbar */ + def addMMTToolBar(view: View) { + invokeLater { + clearMMTToolBar(view) + val viewToolBar = view.getToolBar + if (viewToolBar != null) { + log("adding toolbar...") + val newbar = new MMTToolBar(this) + viewToolBar.add(newbar) + } + } + } + /** removes MMT toolbar */ + def clearMMTToolBar(view: View) { + val viewToolBar = view.getToolBar + if (viewToolBar != null) { + log("Number of components of this view: " + viewToolBar.getComponentCount.toString) + viewToolBar.getComponents foreach {comp => + if(comp.isInstanceOf[MMTToolBar]) { + log("removing tool bar") + viewToolBar.remove(comp) + } + } + } + } +} + +object MMTPlugin { + def isIDChar(c: Char) = (! Character.isWhitespace(c)) && "()[]{}:.".forall(_ != c) + /** finds the id at a certain offset in a buffer + * @param buffer a buffer + * @param index offset in the buffer + * @return the id at the offset, if any, as (line,beginOffsetInBuffer,endOffsetInBuffer,id) + */ + def getCurrentID(buffer: Buffer, index: Int) : Option[(Int,Int,Int,String)] = { + val line = buffer.getLineOfOffset(index) + val lineStart = buffer.getLineStartOffset(line) + val lineLength = buffer.getLineLength(line) + if (lineLength == 0) + return None + var offset = index - lineStart + val lineText = buffer.getLineText(line) + if (offset == lineLength) + offset = offset - 1 + if (! isIDChar(lineText(offset))) + return None + var left = offset // first character of id + while (left > 0 && isIDChar(lineText(left - 1))) {left = left - 1} + var right = offset // last character of id + while (right < lineLength - 1 && isIDChar(lineText(right + 1))) {right = right + 1} + Some((line, lineStart + left, lineStart + right + 1, lineText.substring(left, right + 1))) + } +} + +object StatusBarLogger extends ReportHandler("jEdit") { + def apply(ind: Int, caller: => String, group: String, msg: List[String]) { + val v = jEdit.getActiveView + if (v != null) { + v.getStatus.setMessage("MMT " + group + ": " + msg.headOption.getOrElse("")) + } + } +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTRefactorDockable.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTRefactorDockable.scala index c61ae68ef0..2be0e616bc 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTRefactorDockable.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTRefactorDockable.scala @@ -21,7 +21,7 @@ class MMTRefactorDockable(jview: View, position: String) extends JPanel { } object Publisher { - def publish(jview:View)(s:List[DeclaredModule]): Unit = { + def publish(jview:View)(s:List[DeclaredModule]) { implicit val rh = new presentation.StringBuilder val presenter = new MMTSyntaxPresenter controller.extman.addExtension(presenter) @@ -34,4 +34,4 @@ object Publisher { } val controller = jEdit.getPlugin("info.kwarc.mmt.jedit.MMTPlugin", true).asInstanceOf[MMTPlugin].controller -} \ No newline at end of file +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTSideKick.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTSideKick.scala index 3c16a26b2a..bc1f8f757c 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTSideKick.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTSideKick.scala @@ -1,328 +1,387 @@ -package info.kwarc.mmt.jedit - -import javax.swing.tree.DefaultMutableTreeNode - -import org.gjt.sp.jedit._ -import sidekick._ -import errorlist._ - -import info.kwarc.mmt.api._ -import info.kwarc.mmt.api.checking._ -import info.kwarc.mmt.api.documents._ -import info.kwarc.mmt.api.frontend._ -import info.kwarc.mmt.api.libraries._ -import info.kwarc.mmt.api.modules._ -import info.kwarc.mmt.api.notations._ -import info.kwarc.mmt.api.objects._ -import info.kwarc.mmt.api.parser._ -import info.kwarc.mmt.api.symbols._ -import info.kwarc.mmt.api.utils._ - -class MMTSideKick extends SideKickParser("mmt") with Logger { - // gets jEdit's instance of MMTPlugin, jEdit will load the plugin if it is not loaded yet - val mmt : MMTPlugin = jEdit.getPlugin("info.kwarc.mmt.jedit.MMTPlugin", true).asInstanceOf[MMTPlugin] - val controller = mmt.controller - val logPrefix = "jedit-sidekick" - val report = controller.report - - // override def stop() - // override def getParseTriggers : String = "" - - override def supportsCompletion = true - override def canCompleteAnywhere = true - // override def getInstantCompletionTriggers : String = "" - override def complete(editPane: EditPane, caret : Int) : SideKickCompletion = { - val textArea = editPane.getTextArea - val view = editPane.getView - val asset = MMTSideKick.getAssetAtOffset(view,caret).getOrElse(return null) - asset match { - case a: MMTObjAsset => - a.obj match { - case Hole(t) => - // run theorem prover to find options to fill the hole - val g = new proving.Goal(a.context, t) - val rules = RuleSet.collectRules(controller, a.context) //TODO should be cached - val pu = proving.ProvingUnit(None, g.context, g.conc, logPrefix) - val prover = new proving.Searcher(controller, g, rules, pu) - log(g.present(2)(prover.presentObj, None,None)) - val options = prover.interactive(3) - val comp = new ProverCompletion(view, controller, a.region, options) - return comp - case o => - // insert hole for the definiens of a constant whose type is known - if (a.parent.component == DefComponent) { - controller.globalLookup.getComponent(a.parent) match { - case defTc: TermContainer if defTc.read.getOrElse("").trim.isEmpty => - controller.globalLookup.getComponent(a.parent.parent $ TypeComponent) match { - case tpTc: TermContainer if tpTc.analyzed.isDefined => - val option = Hole(tpTc.analyzed.get) - return new ProverCompletion(view, controller, a.region, List(option)) - case _ => - } - case _ => - } - } - } - case _ => - } - asset.getScope match { - case Some(a) => - val p = textArea.getCaretPosition - var l = 0 // number of character to the left of the caret that are id characters - while (l < p && MMTPlugin.isIDChar(textArea.getText(p - l - 1,1)(0))) {l = l + 1} - val partialName = textArea.getText(p - l, l) - val compls = Names.resolve(OMMOD(a), Nil, partialName)(controller.localLookup) - val paths = compls.map(_.path) - val symbols = paths.flatMap {p => - controller.globalLookup.getO(p) match { - case Some(c: Constant) => List(c) - case _ => Nil - } - } - val displayed = symbols map {c => - c.tp match { - case Some(t) => c.name.toPath + " : " + controller.presenter.asString(t) - case None => c.name.toPath - } - } - return new IDCompletion(view, controller, symbols, partialName, displayed) - case None => - } - new IDCompletion(view, controller, Nil, "", Nil) - } - - def parse(buffer: Buffer, errorSource: DefaultErrorSource) : SideKickParsedData = { - val path = File(buffer.getPath) - val errorCont = new ErrorListForwarder(mmt.errorSource, controller, path) - //TODO there is a synchronization problem with multiple parse calls causing a concurrent access exception in ErrorList - errorCont.reset - try { - val uri = utils.FileURI(path) - val text = buffer.getText - val nsMap = controller.getNamespaceMap - val ps = controller.backend.resolvePhysical(path) orElse controller.backend.resolveAnyPhysicalAndLoad(path) match { - case None => - ParsingStream.fromString(text, DPath(uri), path.getExtension.getOrElse(""), Some(nsMap)) - case Some((a, p)) => - ParsingStream.fromSourceFile(a, FilePath(p), Some(ParsingStream.stringToReader(text)), Some(nsMap)) - } - log("parsing " + path) - val tree = new SideKickParsedData(path.toJava.getName) - val root = tree.root - // read the document in a task that can be cancelled by the stop method - val doc = controller.read(ps, true, true)(errorCont) match { - case d: Document => d - case _ => throw ImplementationError("document expected") - } - currentTask = Some(ps) - // add narrative structure of doc to outline tree - buildTreeDoc(root, doc) - tree - } catch {case e: Exception => - val msg = e.getClass + ": " + e.getMessage - val pe = ParseError("unknown error: " + msg).setCausedBy(e) - log(msg) - errorCont(pe) - SideKickParsedData.getParsedData(jEdit.getActiveView) - } - } - - /** stores the current parse task so that it can be stopped by the stop method */ - private var currentTask: Option[MMTTask] = None - // this is called from another tread and should interrupt parsing - override def stop { - // this may cause an inconsistent state but calling clear in parse method should fix most problems - currentTask.foreach {_.kill(() => ())} - } - - private def getRegion(e: metadata.HasMetaData) : Option[SourceRegion] = SourceRef.get(e).map(_.region) - - /* build the sidekick outline tree: document node */ - private def buildTreeDoc(node: DefaultMutableTreeNode, doc: Document) { - val reg = getRegion(doc) getOrElse SourceRegion(SourcePosition(0,0,0),SourcePosition(0,0,0)) - val child = new DefaultMutableTreeNode(new MMTElemAsset(doc, doc.path.last, reg)) - node.add(child) - doc.getDeclarations foreach { - case d: Document => - buildTreeDoc(child, d) - case r: NRef => - val rReg = getRegion(r) getOrElse reg - val rChild = new DefaultMutableTreeNode(new MMTURIAsset(r.target, rReg)) - r match { - case d: DRef => - child.add(rChild) - case m: MRef => - try { - val mod = controller.localLookup.getModule(m.target) - buildTreeMod(child, mod, Context.empty, reg) - } catch {case e: Error => - // graceful degradation in case module could not be parsed - child.add(rChild) - } - case s: SRef => - } - case oe: opaque.OpaqueElement => - } - } - - private def moduleLabel(m: Module) = m match { - case _ : Theory => "theory" - case _: modules.View => "view" - } - - /* build the sidekick outline tree: module node */ - private def buildTreeMod(node: DefaultMutableTreeNode, mod: Module, context: Context, defaultReg: SourceRegion) { - val reg = getRegion(mod) getOrElse SourceRegion(defaultReg.start,defaultReg.start) - val child = new DefaultMutableTreeNode(new MMTElemAsset(mod, moduleLabel(mod) + " " + mod.path.last, reg)) - node.add(child) - buildTreeComps(child, mod, context, reg) - mod match { - case m: DeclaredModule => - m.getPrimitiveDeclarations foreach {d => buildTreeDecl(child, d, context ++ m.getInnerContext, reg)} - case m: DefinedModule => - } - } - /** build the sidekick outline tree: declaration (in a module) node */ - private def buildTreeDecl(node: DefaultMutableTreeNode, dec: Declaration, context: Context, defaultReg: SourceRegion) { - val reg = getRegion(dec) getOrElse SourceRegion(defaultReg.start,defaultReg.start) - dec match { - case nm: NestedModule if !nm.isInstanceOf[DerivedDeclaration] => - buildTreeMod(node, nm.module, context, reg) - return - case _ => - } - val label = dec match { - case PlainInclude(from,_) => "include " + from.last - case PlainViewInclude(_,_,incl) => "include " + incl.last - case r: RuleConstant => r.feature - case d => d.feature + " " + d.name.toString - } - val child = new DefaultMutableTreeNode(new MMTElemAsset(dec, label, reg)) - node.add(child) - buildTreeComps(child, dec, context, reg) - dec match { - case dd: DerivedDeclaration => - val sf = controller.extman.get(classOf[StructuralFeature], dd.feature).getOrElse {throw ImplementationError("unknown feature: " + dd.feature)} - dd.module.getPrimitiveDeclarations foreach {d => buildTreeDecl(child, d, context ++ sf.getInnerContext(dd), reg)} - case _ => - } - } - - /** add child nodes for all components of an element */ - private def buildTreeComps(node: DefaultMutableTreeNode, ce: ContentElement, context: Context, defaultReg: SourceRegion) { - ce.getComponents foreach { - case DeclarationComponent(comp, cont: AbstractTermContainer) if cont.get.isDefined => - buildTreeComp(node, ce.path $ comp, cont.get.get, context, defaultReg) - case NotationComponent(comp, cont) => - buildTreeNot(node, ce.path, cont, comp, defaultReg) - case _ => - } - } - - /** build the sidekick outline tree: component of a (module or symbol level) declaration */ - private def buildTreeComp(node: DefaultMutableTreeNode, parent: CPath, t: Term, context: Context, defaultReg: SourceRegion) { - val reg = getRegion(t) getOrElse SourceRegion.none - val child = new DefaultMutableTreeNode(new MMTObjAsset(t, t, context, parent, parent.component.toString, reg)) - node.add(child) - buildTreeTerm(child, parent, t, context, defaultReg) - } - - /** build the sidekick outline tree: notations */ - private def buildTreeNot(node: DefaultMutableTreeNode, owner: ContentPath, cont: NotationContainer, comp: NotationComponentKey, defaultReg: SourceRegion) { - val tn = cont(comp).get // always defined here - val reg = getRegion(tn) getOrElse SourceRegion(defaultReg.start,defaultReg.start) - val label = comp match { - case ParsingNotationComponent => "notation (parsing)" - case PresentationNotationComponent => "notation (presentation)" - case VerbalizationNotationComponent => "notation (verbalization)" - } - val child = new DefaultMutableTreeNode(new MMTNotAsset(owner, label + ": " + tn.toString, tn, reg)) - node.add(child) - } - - /** build the sidekick outline tree: context node (each VarDecl is added individually) */ - private def buildTreeCont(node: DefaultMutableTreeNode, parent: CPath, con: Context, context: Context, defaultReg: SourceRegion) { - con mapVarDecls {case (previous, vd @ VarDecl(n, f, tp, df, _)) => - val reg = getRegion(vd) getOrElse SourceRegion(defaultReg.start,defaultReg.start) - val currentContext = context ++ previous - val child = new DefaultMutableTreeNode(new MMTObjAsset(vd, vd, currentContext, parent, f.map(_+" ").getOrElse("") + n.toString, reg)) - node.add(child) - (tp.toList:::df.toList) foreach {t => - buildTreeTerm(child, parent, t, currentContext, reg) - } - } - } - - /** build the sidekick outline tree: (sub)term node */ - private def buildTreeTerm(node: DefaultMutableTreeNode, parent: CPath, t: Term, context: Context, _unused_defaultReg: SourceRegion) { - var extraLabel = "" - val reg = getRegion(t) getOrElse { - extraLabel = " [not in source]" // lack of source region indicates inferred subterms - SourceRegion.none - } - val tP = controller.pragmatic.mostPragmatic(t) - val label = tP match { - case OMV(n) => n.toString - case OMID(p) => p.name.toString - case l: OMLITTrait => l.toString - case OML(nm,_,_,_,_) => nm.toString - case OMSemiFormal(_) => "unparsed: " + tP.toString - case ComplexTerm(op, _,_,_) => op.last.toString - case OMA(OMID(p),_) => p.name.last.toString - case OMBINDC(OMID(p),_,_) => p.name.last.toString - case OMA(ct,args) => "OMA" // TODO probably shouldn't occur, but throws errors! - } - val child = new DefaultMutableTreeNode(new MMTObjAsset(t, tP, context, parent, label+extraLabel, reg)) - node.add(child) - tP match { - case OML(_,tp,df,_,_) => - (tp.toList:::df.toList) foreach {t => - buildTreeTerm(child, parent, t, context, reg) - } - case OMBINDC(binder,cont, scopes) => - if (! binder.isInstanceOf[OMID]) - buildTreeTerm(child, parent, binder, context, reg) - buildTreeCont(child, parent, cont, context, reg) - scopes foreach {s => - buildTreeTerm(child, parent, s, context ++ cont, reg) - } - case OMA(fun, args) => - if (! fun.isInstanceOf[OMID]) - buildTreeTerm(child, parent, fun, context, reg) - args.foreach(buildTreeTerm(child, parent, _, context, reg)) - case _ => t.subobjects foreach { - case (_, o: Term) => buildTreeTerm(child, parent, o, context, reg) - case _ => - } - } - } -} - -object MMTSideKick { - /** @return the asset at the specified position */ - def getAssetAtOffset(view: org.gjt.sp.jedit.View, caret: Int) = { - val pd = SideKickParsedData.getParsedData(view) - pd.getAssetAtOffset(caret) match { - case ma : MMTAsset => Some(ma) - case _ => None - } - } - /** @return the smallest asset covering the specified range */ - def getAssetAtRange(view: org.gjt.sp.jedit.View, begin: Int, end: Int) = { - val pd = SideKickParsedData.getParsedData(view) - var path = pd.getTreePathForPosition(begin) - var asset: MMTAsset = null - while ({ - val a = path.getLastPathComponent.asInstanceOf[DefaultMutableTreeNode].getUserObject - a match { - case m: MMTAsset => - asset = m - m.getEnd.getOffset < end - case _ => false - } - }) { - path = path.getParentPath - } - asset - } -} +package info.kwarc.mmt.jedit + +import javax.swing.tree.DefaultMutableTreeNode + +import org.gjt.sp.jedit +import jedit._ +import sidekick._ +import errorlist._ + +import info.kwarc.mmt.api._ +import info.kwarc.mmt.api.checking._ +import info.kwarc.mmt.api.documents._ +import info.kwarc.mmt.api.frontend._ +import info.kwarc.mmt.api.libraries._ +import info.kwarc.mmt.api.modules._ +import info.kwarc.mmt.api.notations._ +import info.kwarc.mmt.api.objects._ +import info.kwarc.mmt.api.parser._ +import info.kwarc.mmt.api.symbols._ +import info.kwarc.mmt.api.utils._ + +class MMTSideKick extends SideKickParser("mmt") with Logger { + // gets jEdit's instance of MMTPlugin, jEdit will load the plugin if it is not loaded yet + val mmt : MMTPlugin = jEdit.getPlugin("info.kwarc.mmt.jedit.MMTPlugin", true).asInstanceOf[MMTPlugin] + val controller = mmt.controller + val logPrefix = "jedit-sidekick" + val report = controller.report + + // override def stop() + // override def getParseTriggers : String = "" + + override def supportsCompletion = true + override def canCompleteAnywhere = true + // override def getInstantCompletionTriggers : String = "" + override def complete(editPane: EditPane, caret : Int) : SideKickCompletion = { + val textArea = editPane.getTextArea + val view = editPane.getView + val asset = MMTSideKick.getAssetAtOffset(view,caret).getOrElse(return null) + asset match { + case a: MMTObjAsset => + a.obj match { + case Hole(t) => + // run theorem prover to find options to fill the hole + val g = new proving.Goal(a.context, t) + val rules = RuleSet.collectRules(controller, a.context) //TODO should be cached + val pu = proving.ProvingUnit(None, g.context, g.conc, logPrefix) + val prover = new proving.Searcher(controller, g, rules, pu) + log(g.present(2)(prover.presentObj, None,None)) + val options = prover.interactive(3) + val comp = new ProverCompletion(view, controller, a.region, options) + return comp + case o => + // insert hole for the definiens of a constant whose type is known + if (a.parent.component == DefComponent) { + controller.globalLookup.getComponent(a.parent) match { + case defTc: TermContainer if defTc.read.getOrElse("").trim.isEmpty => + controller.globalLookup.getComponent(a.parent.parent $ TypeComponent) match { + case tpTc: TermContainer if tpTc.analyzed.isDefined => + val option = Hole(tpTc.analyzed.get) + return new ProverCompletion(view, controller, a.region, List(option)) + case _ => + } + case _ => + } + } + } + case _ => + } + asset.getScope match { + case Some(a) => + val p = textArea.getCaretPosition + var l = 0 // number of character to the left of the caret that are id characters + while (l < p && MMTPlugin.isIDChar(textArea.getText(p - l - 1,1)(0))) {l = l + 1} + val partialName = textArea.getText(p - l, l) + val compls = Names.resolve(OMMOD(a), Nil, partialName)(controller.localLookup) + val paths = compls.map(_.path) + val symbols = paths.flatMap {p => + controller.globalLookup.getO(p) match { + case Some(c: Constant) => List(c) + case _ => Nil + } + } + val displayed = symbols map {c => + c.tp match { + case Some(t) => c.name.toPath + " : " + controller.presenter.asString(t) + case None => c.name.toPath + } + } + return new IDCompletion(view, controller, symbols, partialName, displayed) + case None => + } + new IDCompletion(view, controller, Nil, "", Nil) + } + + def parse(buffer: Buffer, errorSource: DefaultErrorSource) : SideKickParsedData = { + val path = File(buffer.getPath) + val errorCont = new ErrorListForwarder(mmt.errorSource, controller, path) + //TODO there is a synchronization problem with multiple parse calls causing a concurrent access exception in ErrorList + errorCont.reset + try { + val uri = utils.FileURI(path) + val text = buffer.getText + val nsMap = controller.getNamespaceMap + val ps = controller.backend.resolvePhysical(path) orElse controller.backend.resolveAnyPhysicalAndLoad(path) match { + case None => + ParsingStream.fromString(text, DPath(uri), path.getExtension.getOrElse(""), Some(nsMap)) + case Some((a, p)) => + ParsingStream.fromSourceFile(a, FilePath(p), Some(ParsingStream.stringToReader(text)), Some(nsMap)) + } + log("parsing " + path) + val tree = new SideKickParsedData(path.toJava.getName) + val root = tree.root + // read the document in a task that can be cancelled by the stop method + val doc = controller.read(ps, true, true)(errorCont) match { + case d: Document => d + case _ => throw ImplementationError("document expected") + } + currentTask = Some(ps) + // add narrative structure of doc to outline tree + buildTreeDoc(root, doc) + tree + } catch { + case e: Throwable => + val msg = e.getClass + ": " + e.getMessage + val pe = ParseError("unknown error: " + msg).setCausedBy(e) + log(msg) + try {errorCont(pe)} catch {case e: Exception => log(Error(e).toStringLong)} + SideKickParsedData.getParsedData(jEdit.getActiveView) + } + } + + /** stores the current parse task so that it can be stopped by the stop method */ + private var currentTask: Option[MMTTask] = None + // this is called from another tread and should interrupt parsing + override def stop { + // this may cause an inconsistent state but calling clear in parse method should fix most problems + currentTask.foreach {_.kill(() => ())} + } + + private def getRegion(e: metadata.HasMetaData) : Option[SourceRegion] = SourceRef.get(e).map(_.region) + + /* build the sidekick outline tree: document node */ + private def buildTreeDoc(node: DefaultMutableTreeNode, doc: Document) { + val reg = getRegion(doc) getOrElse SourceRegion(SourcePosition(0,0,0),SourcePosition(0,0,0)) + val child = new DefaultMutableTreeNode(new MMTElemAsset(doc, doc.path.last, reg)) + node.add(child) + doc.getDeclarations foreach { + case d: Document => + buildTreeDoc(child, d) + case r: NRef => + val rReg = getRegion(r) getOrElse reg + val rChild = new DefaultMutableTreeNode(new MMTURIAsset(r.target, rReg)) + r match { + case d: DRef => + child.add(rChild) + case m: MRef => + try { + val mod = controller.localLookup.getModule(m.target) + buildTreeMod(child, mod, Context.empty, reg) + } catch {case e: Error => + // graceful degradation in case module could not be parsed + child.add(rChild) + } + case s: SRef => + } + case oe: opaque.OpaqueElement => + } + } + + private def moduleLabel(m: Module) = m match { + case _ : Theory => "theory" + case _: modules.View => "view" + } + + /* build the sidekick outline tree: module node */ + private def buildTreeMod(node: DefaultMutableTreeNode, mod: Module, context: Context, defaultReg: SourceRegion) { + val reg = getRegion(mod) getOrElse SourceRegion(defaultReg.start,defaultReg.start) + val child = new DefaultMutableTreeNode(new MMTElemAsset(mod, moduleLabel(mod) + " " + mod.path.last, reg)) + node.add(child) + buildTreeComps(child, mod, context, reg) + mod match { + case m: DeclaredModule => + val defElab = m.getDeclarations.filter(_.getOrigin == ElaborationOfDefinition) + if (defElab.nonEmpty) { + val elabChild = new DefaultMutableTreeNode(new MMTAuxAsset("-- flat definition --")) + child.add(elabChild) + defElab foreach {d => buildTreeDecl(elabChild, m, d, context ++ m.getInnerContext, reg)} + } + val incls = m.getDeclarations.filter {d => Include.unapply(d).isDefined && d.isGenerated} + if (incls.nonEmpty) { + val inclsChild = new DefaultMutableTreeNode(new MMTAuxAsset("-- flat includes --")) + child.add(inclsChild) + incls foreach {d => buildTreeDecl(inclsChild, m, d, context ++ m.getInnerContext, reg)} + } + m.getPrimitiveDeclarations foreach {d => buildTreeDecl(child, m, d, context ++ m.getInnerContext, reg)} + case m: DefinedModule => + } + } + /** build the sidekick outline tree: declaration (in a module) node */ + private def buildTreeDecl(node: DefaultMutableTreeNode, parent: ContainerElement[_ <: Declaration], dec: Declaration, context: Context, defaultReg: SourceRegion) { + val reg = getRegion(dec) getOrElse SourceRegion(defaultReg.start,defaultReg.start) + dec match { + case nm: NestedModule if !nm.isInstanceOf[DerivedDeclaration] => + buildTreeMod(node, nm.module, context, reg) + return + case _ => + } + val label = dec match { + case Include(_, from,_) => "include " + from.last + case LinkInclude(_,_,OMMOD(incl)) => "include " + incl.last + case r: RuleConstant => r.feature + case d => d.feature + " " + d.name.toStr(true) + } + val child = new DefaultMutableTreeNode(new MMTElemAsset(dec, label, reg)) + node.add(child) + buildTreeComps(child, dec, context, reg) + dec match { + case ce: ContainerElement[Declaration]@unchecked => // declarations can only contain declarations + val contextInner = context ++ controller.getExtraInnerContext(ce) + dec.getDeclarations foreach {d => buildTreeDecl(child, ce, d, contextInner, reg)} + case _ => + } + // a child with all declarations elaborated from dec + val elab = parent.getDeclarations.filter(_.getOrigin == ElaborationOf(dec.path)) + if (elab.nonEmpty) { + val elabChild = new DefaultMutableTreeNode(new MMTAuxAsset("-- elaboration --")) + child.add(elabChild) + elab foreach {e => buildTreeDecl(elabChild, parent, e, context, defaultReg)} + } + } + + /** add child nodes for all components of an element */ + private def buildTreeComps(node: DefaultMutableTreeNode, ce: ContentElement, context: Context, defaultReg: SourceRegion) { + ce.getComponents foreach { + case DeclarationComponent(comp, cont: AbstractTermContainer) if cont.get.isDefined => + buildTreeComp(node, ce.path $ comp, cont.get.get, context, defaultReg) + case NotationComponent(comp, cont) => + buildTreeNot(node, ce.path, cont, comp, defaultReg) + case _ => + } + } + + /** build the sidekick outline tree: component of a (module or symbol level) declaration */ + private def buildTreeComp(node: DefaultMutableTreeNode, parent: CPath, t: Term, context: Context, defaultReg: SourceRegion) { + val reg = getRegion(t) getOrElse SourceRegion.none + val child = new DefaultMutableTreeNode(new MMTObjAsset(mmt, t, t, context, parent, parent.component.toString, reg)) + node.add(child) + buildTreeTerm(child, parent, t, context, defaultReg) + } + + /** build the sidekick outline tree: notations */ + private def buildTreeNot(node: DefaultMutableTreeNode, owner: ContentPath, cont: NotationContainer, comp: NotationComponentKey, defaultReg: SourceRegion) { + val tn = cont(comp).get // always defined here + val reg = getRegion(tn) getOrElse SourceRegion(defaultReg.start,defaultReg.start) + val label = comp match { + case ParsingNotationComponent => "notation (parsing)" + case PresentationNotationComponent => "notation (presentation)" + case VerbalizationNotationComponent => "notation (verbalization)" + } + val child = new DefaultMutableTreeNode(new MMTNotAsset(owner, label, tn, reg)) + node.add(child) + } + + /** build the sidekick outline tree: context node (each VarDecl is added individually) */ + private def buildTreeCont(node: DefaultMutableTreeNode, parent: CPath, con: Context, context: Context, defaultReg: SourceRegion) { + con mapVarDecls {case (previous, vd @ VarDecl(n, f, tp, df, _)) => + val reg = getRegion(vd) getOrElse SourceRegion(defaultReg.start,defaultReg.start) + val currentContext = context ++ previous + val child = new DefaultMutableTreeNode(new MMTObjAsset(mmt, vd, vd, currentContext, parent, f.map(_+" ").getOrElse("") + n.toString, reg)) + node.add(child) + (tp.toList:::df.toList) foreach {t => + buildTreeTerm(child, parent, t, currentContext, reg) + } + } + } + + /** build the sidekick outline tree: (sub)term node */ + private def buildTreeTerm(node: DefaultMutableTreeNode, parent: CPath, t: Term, context: Context, _unused_defaultReg: SourceRegion) { + var extraLabel = "" + val reg = getRegion(t) getOrElse { + extraLabel = " [not in source]" // lack of source region indicates inferred subterms + SourceRegion.none + } + val tP = controller.pragmatic.mostPragmatic(t) + val label = tP match { + case OMV(n) => n.toString + case OMID(p) => p.name.toString + case l: OMLITTrait => l.toString + case OML(nm,_,_,_,_) => nm.toString + case OMSemiFormal(_) => "unparsed: " + tP.toString + case ComplexTerm(op, _,_,_) => op.name.last.toStr(true) + case OMA(OMID(p),_) => p.name.last.toStr(true) + case OMBINDC(OMID(p),_,_) => p.name.last.toStr(true) + case OMA(ct,args) => "OMA" // TODO probably shouldn't occur, but throws errors! + } + val asset = new MMTObjAsset(mmt, t, tP, context, parent, label+extraLabel, reg) + val child = new DefaultMutableTreeNode(asset) + node.add(child) + tP match { + case OML(_,tp,df,_,_) => + (tp.toList:::df.toList) foreach {t => + buildTreeTerm(child, parent, t, context, reg) + } + case OMBINDC(binder,cont, scopes) => + if (! binder.isInstanceOf[OMID]) + buildTreeTerm(child, parent, binder, context, reg) + buildTreeCont(child, parent, cont, context, reg) + scopes foreach {s => + buildTreeTerm(child, parent, s, context ++ cont, reg) + } + case OMA(fun, args) => + if (! fun.isInstanceOf[OMID]) + buildTreeTerm(child, parent, fun, context, reg) + args.foreach(buildTreeTerm(child, parent, _, context, reg)) + case _ => t.subobjects foreach { + case (_, o: Term) => buildTreeTerm(child, parent, o, context, reg) + case _ => + } + } + } +} + +object MMTSideKick { + /** @return the asset at the specified position */ + def getAssetAtOffset(view: jedit.View, offset: Int): Option[MMTAsset] = { + val pd = SideKickParsedData.getParsedData(view) + pd.getAssetAtOffset(offset) match { + case ma : MMTAsset => Some(ma) + case _ => None + } + } + + /** @return the smallest asset covering the specified range (inclusive begin, exclusive end) */ + def getAssetAtRange(view: jedit.View, begin: Int, end: Int): Option[MMTAsset] = { + val pd = SideKickParsedData.getParsedData(view) + var path = pd.getTreePathForPosition(begin) + var asset: Option[MMTAsset] = None + while ({ + val a = path.getLastPathComponent.asInstanceOf[DefaultMutableTreeNode].getUserObject + a match { + case m: MMTAsset => + asset = Some(m) + m.getEnd.getOffset+1 < end + case _ => false + } + }) { + path = path.getParentPath + } + asset + } + + /** + * return the smallest asset covering the first selection or (if no selection) the asset at the the cursor; boolean is true if the former case + * this is useful for button or key interaction, where a selection or cursor position must be used to determine an asset + */ + def getCurrentAsset(view: jedit.View): Option[(MMTAsset,Boolean)] = { + val ta = view.getTextArea + ta.getSelectionCount match { + case 0 => + getAssetAtOffset(view, ta.getCaretPosition) map {x => (x,false)} + case _ => + val sel = ta.getSelection(0) + getAssetAtRange(view, sel.getStart, sel.getEnd) map {x => (x,true)} + } + } + + /** + * like getAssetAtOffset, but includes the surrounding selection, if any; the boolean if true if the area is selected + * this is useful for mouse interaction, where an offset can be computed from the mouse pointer position + */ + def getSelectedAssetAtOffset(view: jedit.View, offset: Int): Option[(MMTAsset,Boolean)] = { + val rangeOpt = getSelectedRangeAroundOffset(view.getTextArea, offset) + rangeOpt match { + case Some((b,e)) => getAssetAtRange(view, b, e) map {x => (x,true)} + case None => getAssetAtOffset(view, offset) map {x => (x,false)} + } + } + /** the range of the selection at a position (selection inclusive begin, exclusive end) */ + def getSelectedRangeAroundOffset(ta: textarea.TextArea, offset: Int): Option[(Int,Int)] = { + if (ta.getSelectionCount != 1) return None + val sel = ta.getSelection(0) + if (sel.getStart <= offset && offset < sel.getEnd) + Some((sel.getStart, sel.getEnd)) + else + None + } +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTTextAreaExtension.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTTextAreaExtension.scala index ff2768cc77..5f240d23ae 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTTextAreaExtension.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTTextAreaExtension.scala @@ -1,248 +1,239 @@ -package info.kwarc.mmt.jedit - -import info.kwarc.mmt.api._ -import frontend._ -import objects._ - -import org.gjt.sp.jedit._ -import textarea._ -import syntax._ -import javax.swing.text.Segment -import java.awt.Font -import java.awt.font.TextAttribute -import javax.swing.ImageIcon - -/** A TextAreaExtension that is added to every EditPane - * it can be used for custom painting, e.g., background highlighting, tooltips - * Currently it highlights terminator characters - */ -class MMTTextAreaExtension(controller: Controller, editPane: EditPane) extends TextAreaExtension { - private def log(msg: String) {controller.report("jedit-painter", msg)} - private val textArea = editPane.getTextArea - private val view = editPane.getView - private val painter = textArea.getPainter - - //val oIMG = new ImageIcon(this.getClass().getResource("/images/object_t.png")).getImage() - //val dIMG = new ImageIcon(this.getClass().getResource("/images/clear_button.png")).getImage() - //val mIMG = new ImageIcon(this.getClass().getResource("/images/clear_button.png")).getImage() - - import java.awt.{Point,Color} - - // imperatively reusing the same variables for efficiency - private val segment = new Segment - private val startPoint = new Point - // parameters for coloring the delimiters - private val high = 255 - private val low = 192 - - override def paintValidLine(gfx: java.awt.Graphics2D, screenLine: Int, physicalLine: Int, startOffset: Int, endOffset: Int, y: Int) { - if (editPane.getBuffer.getMode.getName != "mmt") return - // the current default font - val font = painter.getFont - val height = painter.getFontHeight - val width = painter.getFontMetrics.getWidths()(29) - /** the background color if we paint the current line and the current line is to be highlighted */ - val lineHighlightBgColor : Option[Color] = { - val caret = textArea.getCaretPosition - if (painter.isLineHighlightEnabled && startOffset <= caret && caret < endOffset) { - Some(painter.getLineHighlightColor) - } else - None - } - // the background color of selected text - val selectionColor = if (textArea.isMultipleSelectionEnabled) painter.getMultipleSelectionColor else painter.getSelectionColor - /** get the background color that jedit already painted */ - def fixedBgColor(offset: Int): Option[Color] = { - if (textArea.getSelectionCount == 0) { - lineHighlightBgColor - } else if (textArea.getSelectionAtOffset(offset) != null) - Some(selectionColor) - else - //TODO if there is a single selection in the current line, jedit is still putting the lineHighlightColor - None - } - /** paints MMT delimiter 'letter' at 'startPoint' with background 'color' */ - def paintDelim(startPoint: Point, color: Color, letter: String) { - gfx.setColor(color) - // left and right edges of rectangle: x and x + width - 1; top and bottom edges: y and y + height - 1 - gfx.fillRect(startPoint.x, startPoint.y, width, height) - gfx.setColor(Color.WHITE) - gfx.setFont(new Font(font.getName(), Font.PLAIN, font.getSize()*2/3)) - gfx.drawString(letter, startPoint.x + width/6, startPoint.y + height*2/3) - } - /** paints other character 'letter' at 'startPoint' using 'style' */ - def paintChar(offset: Int, startPoint: Point, style: SyntaxStyle, c: Char) { - /* We have to erase the text painted by jEdit. We can only do that by painting a rectangle over it. - * To avoid undoing an intended background color and because we cannot look up the color of a pixel, - * we have to reimplement some low level functionality of the TextAreaPainter. - * Specifically, fixedBgColor returns the selection or lineHighlight color (if any). We are currently not using the collapsedFold color. - * Even so, this does not work well, e.g., any change that does not trigger MMT parsing messes up everything. - * Alternatively, we could call removeExtension on paintText and paintTextBackground and then add our own variants. - * But those extension do various additional things that would have to be reimplemented; - * this is difficult because some of those things happen in private methods or even private classes. - * Even keeping the background and repainting the text in background color is difficult because the style that was used is private. - */ - val bgColor = fixedBgColor(offset) orElse Option(style.getBackgroundColor) getOrElse painter.getBackground - gfx.setColor(bgColor) - gfx.fillRect(startPoint.x, startPoint.y, width, height) - gfx.setColor(style.getForegroundColor) - gfx.setFont(style.getFont) - val fm = painter.getFontMetrics - val baseLine = startPoint.y + painter.getFontHeight - (fm.getLeading()+1) - fm.getDescent() // taken from TextAreaPainter#PaintText - gfx.drawString(c.toString, startPoint.x, baseLine) - } - val styles = painter.getStyles - /* chooses a syntax style based on the MMT syntax - * @return Some(tc) if the token class returned by the MMT mode should be overridden with tc - */ - def semanticHighlighting(offset: Int): Option[SyntaxStyle] = { - val as = MMTSideKick.getAssetAtOffset(editPane.getView, offset) - // TODO: make this smarter (see jEdit's syntax highlighting preferences for the available token classes) - /* TODO some objects are missing source references and are marked like their super-term, i.e., as a ComplexTerm - * some OMV's, some OMID's, some top level lambdas in definitions (even though subobjects have source references) - * it's unclear why these objects lose or never acquire their source references - */ - val tcOpt = as match { - case Some(oa: MMTObjAsset) => - val tc = oa.pragmatic match { - case _: OMV => Token.KEYWORD1 - case _: VarDecl => Token.KEYWORD2 // variable in binding - case OMID(op) => - // unapplied operator - if (oa.getScope == Some(op.module)) - Token.KEYWORD3 // operator from current theory - else - Token.KEYWORD4 // operator from meta-theory or included theory - case ComplexTerm(op,_,_,_) => - // applied operator and delimiters - if (oa.getScope == Some(op.module)) - Token.FUNCTION - else - Token.OPERATOR - case _: OMLITTrait => Token.LITERAL1 - case _ => Token.INVALID - } - Some(tc) - case _ => None - } - tcOpt.map(tc => styles(tc)) - } - textArea.getLineText(physicalLine, segment) // stores the line in 'segment' - try { - (0 to segment.length) foreach {localOffset => - val res = textArea.offsetToXY(physicalLine, localOffset, startPoint) - // if res != null: XY-coordinates of global offset assigned to startPoint (relative to the upper left corner of text area) - // if res == null, point not visible (which sometimes happens) - import parser.Reader._ - if (res != null) segment.charAt(localOffset).toInt match { - case c if FS.chars.contains(c) => - paintDelim(startPoint, new Color(high, high, low), "S") - case c if GS is c => - paintDelim(startPoint, new Color(high, low, low), "M") - case c if RS is c => - paintDelim(startPoint, new Color(low, high, low), "D") - case c if US is c => - paintDelim(startPoint, new Color(low, low, high), "O") - case 32 => - case c => - if (MMTOptions.semantichighlighting.get.getOrElse(false)) { - // repaint c if semanticHighlighting returns a result - val globalOffset = segment.offset + localOffset - val styleOpt = semanticHighlighting(globalOffset) - styleOpt foreach {style => - paintChar(globalOffset, startPoint, style, c.toChar) - } - } - } - } - } catch { - // need to hide all exceptions because jEdit removes our painter if it throws exceptions - // e.g., sometimes txtsegm(globalOffset) throws ArrayIndexOutOfBounds - // maybe because the buffer changes while we're painting? - case e:Exception => - // log(e.getClass.toString + ": " + e.getMessage) - } - } - - private def asString(o: Obj) = controller.presenter.asString(o) - private def onSelection(ta: TextArea, offset: Int): Option[(Int,Int)] = { - if (textArea.getSelectionCount != 1) return None - val sel = textArea.getSelection(0) - if (sel.getStart <= offset && offset < sel.getEnd) - Some((sel.getStart, sel.getEnd)) - else - None - } - override def getToolTipText(xCoord: Int, yCoord: Int): String = { - val offset = textArea.xyToOffset(xCoord, yCoord, false) - if (offset == -1) return null - onSelection(textArea,offset) match { - case Some((b,e)) => - val as = try {MMTSideKick.getAssetAtRange(view, b, e)} catch {case ex: Exception => return ex.getClass.toString+ex.getMessage+" " + b + " " + e} - as match { - case ta: MMTObjAsset => - ta.obj match { - case t: Term => - val thy = ta.getScope.getOrElse(return null) - val tp = try { - checking.Solver.infer(controller, Context(thy) ++ ta.context, t, None).getOrElse {throw GetError("error during type inference")} - } catch {case e : Exception => return e.getMessage} - asString(tp) - case _ => return null - } - case _ => return null - } - case None => - val as = MMTSideKick.getAssetAtOffset(view,offset) - as match { - case Some(ta: MMTObjAsset) => - ta.obj match { - case OMV(n) => - asString(ta.context(n)) - case vd : VarDecl => - asString(vd) - case OMA(OMID(p), args) => - val implicits = args.filter(a => parser.SourceRef.get(a).isEmpty) - if (implicits.isEmpty) null - else implicits.map(asString).mkString(" ") - case _ => null - } - case _ => null - } - } - } -} - -//to highlight the current expression implement this -//class MMTMatcher extends org.gjt.sp.jedit.textarea.StructureMatcher -//call editPane.getTextArea().addStructureMatcher, e.g., in sidekick parser's activate method, to register it - -object StyleChanger { - def hidden(style: SyntaxStyle) = { - val newFont = style.getFont.deriveFont(0f) - new SyntaxStyle(style.getForegroundColor, style.getBackgroundColor, newFont) - } - def subscript(style: SyntaxStyle) = { - val attributes = new java.util.Hashtable[TextAttribute,Int] - attributes.put(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB) - val newFont = style.getFont.deriveFont(attributes) - new SyntaxStyle(style.getForegroundColor, style.getBackgroundColor, newFont) - } -} - -/** A TextAreaExtension that is added to a layer below TEXT_LAYER in order to change the painter's styles for a certain mode - * The painter's styles are set by the EditPane according to SyntaxUtilities.loadStyles. - * This class will override that setting. - * Tokens with type COMMENT3 and COMMENT4 will be subscripted resp. hidden, regardless of their style settings. - */ -class StyleChanger(editPane: EditPane, modeName: String) extends TextAreaExtension { - private val textArea = editPane.getTextArea - private val painter = textArea.getPainter - override def paintValidLine(gfx: java.awt.Graphics2D, screenLine: Int, physicalLine: Int, startOffset: Int, endOffset: Int, y: Int) { - if (editPane.getBuffer.getMode.getName == modeName) { - val styles = painter.getStyles - styles(Token.COMMENT4) = StyleChanger.hidden(styles(Token.COMMENT4)) - styles(Token.COMMENT3) = StyleChanger.subscript(styles(Token.COMMENT3)) - } - } -} +package info.kwarc.mmt.jedit + +import info.kwarc.mmt.api._ +import frontend._ +import objects._ + +import org.gjt.sp.jedit._ +import textarea._ +import syntax._ +import javax.swing.text.Segment +import java.awt.Font +import java.awt.font.TextAttribute +import javax.swing.ImageIcon + +/** A TextAreaExtension that is added to every EditPane + * it can be used for custom painting, e.g., background highlighting, tooltips + * Currently it highlights terminator characters + */ +class MMTTextAreaExtension(controller: Controller, editPane: EditPane) extends TextAreaExtension { + private def log(msg: String) {controller.report("jedit-painter", msg)} + private val textArea = editPane.getTextArea + private val view = editPane.getView + private val painter = textArea.getPainter + + //val oIMG = new ImageIcon(this.getClass().getResource("/images/object_t.png")).getImage() + //val dIMG = new ImageIcon(this.getClass().getResource("/images/clear_button.png")).getImage() + //val mIMG = new ImageIcon(this.getClass().getResource("/images/clear_button.png")).getImage() + + import java.awt.{Point,Color} + + // imperatively reusing the same variables for efficiency + private val segment = new Segment + private val startPoint = new Point + // parameters for coloring the delimiters + private val high = 255 + private val low = 192 + + override def paintValidLine(gfx: java.awt.Graphics2D, screenLine: Int, physicalLine: Int, startOffset: Int, endOffset: Int, y: Int) { + if (editPane.getBuffer.getMode.getName != "mmt") return + // the current default font + val font = painter.getFont + val height = painter.getFontHeight + val width = painter.getFontMetrics.getWidths()(29) + /** the background color if we paint the current line and the current line is to be highlighted */ + val lineHighlightBgColor : Option[Color] = { + val caret = textArea.getCaretPosition + if (painter.isLineHighlightEnabled && startOffset <= caret && caret < endOffset) { + Some(painter.getLineHighlightColor) + } else + None + } + // the background color of selected text + val selectionColor = if (textArea.isMultipleSelectionEnabled) painter.getMultipleSelectionColor else painter.getSelectionColor + /** get the background color that jedit already painted */ + def fixedBgColor(offset: Int): Option[Color] = { + if (textArea.getSelectionCount == 0) { + lineHighlightBgColor + } else if (textArea.getSelectionAtOffset(offset) != null) + Some(selectionColor) + else + //TODO if there is a single selection in the current line, jedit is still putting the lineHighlightColor + None + } + /** paints MMT delimiter 'letter' at 'startPoint' with background 'color' */ + def paintDelim(startPoint: Point, color: Color, letter: String) { + gfx.setColor(color) + // left and right edges of rectangle: x and x + width - 1; top and bottom edges: y and y + height - 1 + gfx.fillRect(startPoint.x, startPoint.y, width, height) + gfx.setColor(Color.WHITE) + gfx.setFont(new Font(font.getName(), Font.PLAIN, font.getSize()*2/3)) + gfx.drawString(letter, startPoint.x + width/6, startPoint.y + height*2/3) + } + /** paints other character 'letter' at 'startPoint' using 'style' */ + def paintChar(offset: Int, startPoint: Point, style: SyntaxStyle, c: Char) { + /* We have to erase the text painted by jEdit. We can only do that by painting a rectangle over it. + * To avoid undoing an intended background color and because we cannot look up the color of a pixel, + * we have to reimplement some low level functionality of the TextAreaPainter. + * Specifically, fixedBgColor returns the selection or lineHighlight color (if any). We are currently not using the collapsedFold color. + * Even so, this does not work well, e.g., any change that does not trigger MMT parsing messes up everything. + * Alternatively, we could call removeExtension on paintText and paintTextBackground and then add our own variants. + * But those extension do various additional things that would have to be reimplemented; + * this is difficult because some of those things happen in private methods or even private classes. + * Even keeping the background and repainting the text in background color is difficult because the style that was used is private. + */ + val bgColor = fixedBgColor(offset) orElse Option(style.getBackgroundColor) getOrElse painter.getBackground + gfx.setColor(bgColor) + gfx.fillRect(startPoint.x, startPoint.y, width, height) + gfx.setColor(style.getForegroundColor) + gfx.setFont(style.getFont) + val fm = painter.getFontMetrics + val baseLine = startPoint.y + painter.getFontHeight - (fm.getLeading()+1) - fm.getDescent() // taken from TextAreaPainter#PaintText + gfx.drawString(c.toString, startPoint.x, baseLine) + } + val styles = painter.getStyles + /* chooses a syntax style based on the MMT syntax + * @return Some(tc) if the token class returned by the MMT mode should be overridden with tc + */ + def semanticHighlighting(offset: Int): Option[SyntaxStyle] = { + val as = MMTSideKick.getAssetAtOffset(editPane.getView, offset) + // TODO: make this smarter (see jEdit's syntax highlighting preferences for the available token classes) + /* TODO some objects are missing source references and are marked like their super-term, i.e., as a ComplexTerm + * some OMV's, some OMID's, some top level lambdas in definitions (even though subobjects have source references) + * it's unclear why these objects lose or never acquire their source references + */ + val tcOpt = as match { + case Some(oa: MMTObjAsset) => + val tc = oa.pragmatic match { + case _: OMV => Token.KEYWORD1 + case _: VarDecl => Token.KEYWORD2 // variable in binding + case OMID(op) => + // unapplied operator + if (oa.getScope == Some(op.module)) + Token.KEYWORD3 // operator from current theory + else + Token.KEYWORD4 // operator from meta-theory or included theory + case ComplexTerm(op,_,_,_) => + // applied operator and delimiters + if (oa.getScope == Some(op.module)) + Token.FUNCTION + else + Token.OPERATOR + case _: OMLITTrait => Token.LITERAL1 + case _ => Token.INVALID + } + Some(tc) + case _ => None + } + tcOpt.map(tc => styles(tc)) + } + textArea.getLineText(physicalLine, segment) // stores the line in 'segment' + try { + (0 to segment.length) foreach {localOffset => + val res = textArea.offsetToXY(physicalLine, localOffset, startPoint) + // if res != null: XY-coordinates of global offset assigned to startPoint (relative to the upper left corner of text area) + // if res == null, point not visible (which sometimes happens) + import parser.Reader._ + if (res != null) segment.charAt(localOffset).toInt match { + case c if FS.chars.contains(c) => + paintDelim(startPoint, new Color(high, high, low), "S") + case c if GS is c => + paintDelim(startPoint, new Color(high, low, low), "M") + case c if RS is c => + paintDelim(startPoint, new Color(low, high, low), "D") + case c if US is c => + paintDelim(startPoint, new Color(low, low, high), "O") + case 32 => + case c => + if (MMTOptions.semantichighlighting.get.getOrElse(false)) { + // repaint c if semanticHighlighting returns a result + val globalOffset = segment.offset + localOffset + val styleOpt = semanticHighlighting(globalOffset) + styleOpt foreach {style => + paintChar(globalOffset, startPoint, style, c.toChar) + } + } + } + } + } catch { + // need to hide all exceptions because jEdit removes our painter if it throws exceptions + // e.g., sometimes txtsegm(globalOffset) throws ArrayIndexOutOfBounds + // maybe because the buffer changes while we're painting? + case e:Exception => + // log(e.getClass.toString + ": " + e.getMessage) + } + } + +} + +/** shows tooltips such as type inference (separate from the other TextAreaExtension so that it can be put on a different layer) */ +class MMTToolTips(controller: Controller, editPane: EditPane) extends TextAreaExtension { + private def log(msg: String) {controller.report("tooltips", msg)} + private val textArea = editPane.getTextArea + private val view = editPane.getView + + private def asString(o: Obj) = controller.presenter.asString(o) + + override def getToolTipText(xCoord: Int, yCoord: Int): String = { + val offset = textArea.xyToOffset(xCoord, yCoord, false) + if (offset == -1) return null + val (asset,selected) = MMTSideKick.getSelectedAssetAtOffset(view,offset) getOrElse{return null} + try { + asset match { + case ta: MMTObjAsset => + if (selected) { + ta.inferType.map(asString).getOrElse(null) + } else { + ta.obj match { + case OMV(n) => + asString(ta.context(n)) + case vd : VarDecl => + asString(vd) + case OMA(OMID(p), args) => + val implicits = args.filter(a => parser.SourceRef.get(a).isEmpty) + if (implicits.isEmpty) null + else implicits.map(asString).mkString(" ") + case _ => null + } + } + case _ => null + } + } catch {case e: Exception => + e.getMessage + } + } +} + +//to highlight the current expression implement this +//class MMTMatcher extends org.gjt.sp.jedit.textarea.StructureMatcher +//call editPane.getTextArea().addStructureMatcher, e.g., in sidekick parser's activate method, to register it + +object StyleChanger { + def hidden(style: SyntaxStyle) = { + val newFont = style.getFont.deriveFont(0f) + new SyntaxStyle(style.getForegroundColor, style.getBackgroundColor, newFont) + } + def subscript(style: SyntaxStyle) = { + val attributes = new java.util.Hashtable[TextAttribute,Int] + attributes.put(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB) + val newFont = style.getFont.deriveFont(attributes) + new SyntaxStyle(style.getForegroundColor, style.getBackgroundColor, newFont) + } +} + +/** A TextAreaExtension that is added to a layer below TEXT_LAYER in order to change the painter's styles for a certain mode + * The painter's styles are set by the EditPane according to SyntaxUtilities.loadStyles. + * This class will override that setting. + * Tokens with type COMMENT3 and COMMENT4 will be subscripted resp. hidden, regardless of their style settings. + */ +class StyleChanger(editPane: EditPane, modeName: String) extends TextAreaExtension { + private val textArea = editPane.getTextArea + private val painter = textArea.getPainter + override def paintValidLine(gfx: java.awt.Graphics2D, screenLine: Int, physicalLine: Int, startOffset: Int, endOffset: Int, y: Int) { + if (editPane.getBuffer.getMode.getName == modeName) { + val styles = painter.getStyles + styles(Token.COMMENT4) = StyleChanger.hidden(styles(Token.COMMENT4)) + styles(Token.COMMENT3) = StyleChanger.subscript(styles(Token.COMMENT3)) + } + } +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTToolBar.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTToolBar.scala index 6819215b52..d787d85c87 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTToolBar.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MMTToolBar.scala @@ -19,10 +19,10 @@ class MMTToolBar(mmtp: MMTPlugin) extends JToolBar { private val controller = mmtp.controller private def view = jEdit.getActiveView() - + private def init { val insUS = Swing.Button("O", tooltip = "Inserts object delimiter (US)") { - Inserter.insertUSorTab(view.getTextArea()) + Inserter.insertUSorTab(view.getTextArea()) } val insRS = Swing.Button("D", tooltip = "Inserts declaration delimiter (RS)") { Inserter.insertRSReturn(view.getTextArea()) @@ -30,7 +30,7 @@ class MMTToolBar(mmtp: MMTPlugin) extends JToolBar { val insGS = Swing.Button("M", tooltip = "Inserts module delimiter (GS)") { Inserter.insertGSReturn(view.getTextArea()) } - + val buildButton = Swing.Button("Build", tooltip = "Builds current file") { mmtp.buildActions.buildCurrent(view) } @@ -45,7 +45,7 @@ class MMTToolBar(mmtp: MMTPlugin) extends JToolBar { val clrIMG = (new ImageIcon(this.getClass().getResource("/images/clear_button.png"))).getImage() val clrIMGs = clrIMG.getScaledInstance(16, 16, java.awt.Image.SCALE_SMOOTH ) clrButton.setIcon(new ImageIcon(clrIMGs)) - + val clrFileButton = Swing.Button("Clear File", tooltip = "Clears current file from MMT memory") { val pd = sidekick.SideKickParsedData.getParsedData(view) pd.root.getUserObject match { @@ -67,7 +67,7 @@ class MMTToolBar(mmtp: MMTPlugin) extends JToolBar { add(clrButton) add(clrFileButton) } - + init } diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MouseAdapter.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MouseAdapter.scala index c4885c7ee7..4d8b130e13 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MouseAdapter.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jedit/MouseAdapter.scala @@ -1,23 +1,22 @@ -package info.kwarc.mmt.jedit - -import org.gjt.sp.jedit._ -import textarea._ -import java.awt.event._ - -/** a MouseAdapter that the MMTPlugin adds to a TextAreaPainter in order to control mouse interaction */ -class MMTMouseAdapter(editPane: EditPane) extends MouseAdapter { - private val textArea = editPane.getTextArea - private val view = editPane.getView - override def mouseClicked(e: MouseEvent) { - if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount == 2) { - val as = MMTSideKick.getAssetAtOffset(view, textArea.getCaretPosition) - as match { - case Some(ma: MMTObjAsset) => - val sel = new Selection.Range(ma.region.start.offset, ma.region.end.offset+1) - textArea.setSelection(sel) - //textArea.selectToMatchingBracket - case _ => - } - } - } -} \ No newline at end of file +package info.kwarc.mmt.jedit + +import org.gjt.sp.jedit._ +import textarea._ +import java.awt.event._ + +/** a MouseAdapter that the MMTPlugin adds to a TextAreaPainter in order to control mouse interaction */ +class MMTMouseAdapter(editPane: EditPane) extends MouseAdapter { + private val textArea = editPane.getTextArea + private val view = editPane.getView + override def mouseClicked(e: MouseEvent) { + if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount == 2) { + val as = MMTSideKick.getAssetAtOffset(view, textArea.getCaretPosition) + as match { + case Some(ma: MMTObjAsset) => + textArea.setSelection(ma.toSelection) + //textArea.selectToMatchingBracket + case _ => + } + } + } +} diff --git a/src/jEdit-mmt/src/info/kwarc/mmt/jeditsetup/Setup.scala b/src/jEdit-mmt/src/info/kwarc/mmt/jeditsetup/Setup.scala index f3efee3fd3..1a358bf2e9 100644 --- a/src/jEdit-mmt/src/info/kwarc/mmt/jeditsetup/Setup.scala +++ b/src/jEdit-mmt/src/info/kwarc/mmt/jeditsetup/Setup.scala @@ -13,56 +13,58 @@ import info.kwarc.mmt.jedit._ * * copies jars, modes, abbreviations etc. to jEdit settings directory * installation is idempotent + * + * @param logger Optional function to print interactive setup statements in. Defaults to println */ class Setup extends ShellExtension("jeditsetup") { + def helpText = "needed arguments: (install | uninstall) [JEDIT/SETTINGS/FOLDER]" - def helpText = "needed arguments: (install | install-jars | uninstall) [JEDIT/SETTINGS/FOLDER]" + /** a function tog log a message */ + val log: String => Unit = println /** run method as ShellExtension */ def run(shell: Shell, args: List[String]): Boolean = { val l = args.length if (l <= 0 || l > 2) { - println(helpText) + log(helpText) return true } val jeditOpt = if (l >= 2) Some(File(args(1))) else OS.jEditSettingsFolder val jedit = jeditOpt.getOrElse { - println("The jEdit settings folder was not found. If you have installed jEdit just now, you may have to run it once so that it creates the folder.") + log("The jEdit settings folder was not found. If you have installed jEdit just now, you may have to run it once so that it creates the folder.") return true } val doIt = new DoIt(shell, jedit) if (args(0) == "customize") { doIt.customize - } else { - val (installOpt,fat) = args(0) match { - case "install" => (Some(true),true) - case "uninstall" => (Some(false), true) - case "install-jars" => (Some(true), false) - case "uninstall-jars" => (Some(false), false) - case _ => (None, true) + } else { + val installOpt = args(0) match { + case "install" => Some(true) + case "uninstall" => Some(false) + case _ => None } val install = installOpt.getOrElse { - println(helpText) + log(helpText) return true } if (install) { - println("trying to install to " + jedit) + log("trying to install to " + jedit) } else { - println("trying to uninstall from " + jedit) + log("trying to uninstall from " + jedit) } - doIt.install(install, fat) + doIt.install(install) } true } - + private class DoIt(shell: Shell, jedit: File) { val jarFolder = jedit / "jars" val propsFile = jedit / "properties" val keymapPath = List("keymaps", "imported_keys.props") val rl = shell.runStyle - + def getResource(path: String): String = { rl match { case _: IsFat | OtherStyle => MMTSystem.getResourceAsString(path) @@ -75,7 +77,7 @@ class Setup extends ShellExtension("jeditsetup") { /** merge properties from a resource into a jEdit file */ def mergeProps(propsOldFile: File, propsAddResource: List[String]) { - println("merging " + propsAddResource.mkString("/") + " into " + propsOldFile) + log("merging " + propsAddResource.mkString("/") + " into " + propsOldFile) var propsAdd = utils.stringToList(getPluginResource(propsAddResource), "\\n").flatMap {line => val i = line.indexOf("=") if (!line.startsWith("#") && i != -1) @@ -97,14 +99,14 @@ class Setup extends ShellExtension("jeditsetup") { propsNew = propsNew ::: propsAdd.map(_._2) File.WriteLineWise(propsOldFile, propsNew) } - + /** the actual install/uninstall process * * @param jedit the jEdit settings folder * @param install true/false for install/uninstall * @param fat install fat jar */ - def install(install: Boolean, fat: Boolean) { + def install(install: Boolean) { /** copies or deletes a file depending on install/uninstall, always overwrites existing files */ def copyOrDeleteJar(dir: File, f: List[String], g: List[String]) { if (install) { @@ -118,37 +120,29 @@ class Setup extends ShellExtension("jeditsetup") { val file = jedit / f if (install) { if (!file.exists || replace) { - println("writing: " + file) + log("writing: " + file) File.write(file, getPluginResource(f)) } else { - println("already exists, skipping: " + file) + log("already exists, skipping: " + file) } } else { delete(file) } } - // copy/delete the jars - // see src/project/Utils.scala for sbt - val mainJars = List("mmt-api.jar", "mmt-lf.jar", "MMTPlugin.jar", "mmt-specware.jar", "mmt-pvs.jar") - val libJars = List("scala-library.jar", "scala-parser-combinators.jar", "scala-reflect.jar", "scala-xml.jar", - "tiscaf.jar") - val allJars = List("lfcatalog", "lfcatalog.jar") :: mainJars.map(List("main", _)) ::: libJars.map(List("lib", _)) + // copy/delete the jar jarFolder.mkdirs if (install) { rl match { case rs: IsFat => copyOrDeleteJar(rs.jar, Nil, List("jars", "MMTPlugin.jar")) case nf: DeployRunStyle => - if (fat) - copyOrDeleteJar(nf.deploy, List("mmt.jar"), List("jars", "MMTPlugin.jar")) - else - allJars.foreach(f => copyOrDeleteJar(nf.deploy, f, List("jars", f.last))) + copyOrDeleteJar(nf.deploy, List("mmt.jar"), List("jars", "MMTPlugin.jar")) case OtherStyle => - println("cannot find jar files to install") + log("cannot find jar files to install") } } else { - allJars.foreach(f => delete(jedit / List("jars", f.last))) + delete(jedit / "jars" / "MMTPlugin.jar") } // modes // * copy/delete the mode files @@ -177,7 +171,7 @@ class Setup extends ShellExtension("jeditsetup") { } } if (install || jcat.exists) { - println("updating " + jcat) + log("updating " + jcat) File.WriteLineWise(jcat, newCatalog.reverse) } // abbrevs @@ -204,7 +198,7 @@ class Setup extends ShellExtension("jeditsetup") { } // write new abbrevs if (newAbbrevs.nonEmpty) { - println("updating " + jabb) + log("updating " + jabb) File.WriteLineWise(jabb, newAbbrevs.reverse) } else { delete(jabb) @@ -216,29 +210,29 @@ class Setup extends ShellExtension("jeditsetup") { val d = jedit / plug if (d.isDirectory) { d.deleteDir - println("deleting directory " + d) + log("deleting directory " + d) } } // add properties that depend on MMT installation folder val propsOld = if (propsFile.exists) File.read(propsFile) else "" val archKey = MMTOptions.archives.jeditKey + "=" - if (install) controller.getOAF.map { oaf => - val contentFolder = oaf.root - println("adding property for content folder " + contentFolder) + if (install) controller.getMathHub.map {mh => + val contentFolder = mh.local + log("adding property for content folder " + contentFolder) val encoded = contentFolder.toString.replace("\\", "\\\\").replace(":", "\\:").replace("=", "\\=") val newValues = archKey + encoded val propsNew = propsOld + newValues + "\n" File.write(propsFile, propsNew) } else { - println("deleting property for content folder: " + archKey) + log("deleting property for content folder: " + archKey) val newLines = propsOld.split("\n").filter(!_.startsWith(archKey)).toList if (newLines.nonEmpty && newLines != List("")) { File.WriteLineWise(propsFile, newLines) } else delete(propsFile) } } - - + + val jars = List(("ErrorList", "2.3"), ("SideKick", "1.8"), ("Hyperlinks","1.1.0"), ("Console","5.1.4"), ("BufferTabs","1.2.4")) /** installs plugin dependencies and useful properties */ def customize { @@ -248,18 +242,18 @@ class Setup extends ShellExtension("jeditsetup") { if (!target.exists) { val url = URI(s"https://sourceforge.net/projects/jedit-plugins/files/$name/$version/$name-$version-bin.zip") val zip = target.setExtension("zip") - println("downloading " + url) + log("downloading " + url) try { File.download(url, zip) File.unzip(zip, jarFolder) } catch { - case e: Exception => println(e.getMessage) + case e: Exception => log(e.getMessage) } finally { zip.delete } } } - + // add all properties and keymaps mergeProps(propsFile, List("properties")) mergeProps(jedit / keymapPath, keymapPath) @@ -269,20 +263,20 @@ class Setup extends ShellExtension("jeditsetup") { private def delete(f: File) { if (f.exists && f.isFile) { f.delete - println("deleting " + f) + log("deleting " + f) } } private def copy(from: File, to: File, overwrite: Boolean) { if (to.exists && !overwrite) { - println("warning: " + to + " already exists, skipping; you probably want to run uninstall first") + log("warning: " + to + " already exists, skipping; you probably want to run uninstall first") } else { - println("copying " + from + " to " + to) + log("copying " + from + " to " + to) val success = File.copy(from, to, overwrite) if (!success) { - println("warning: " + from + " does not exist! (skipping)") - println("jedit setup may be incomplete or inconsistent.") + log("warning: " + from + " does not exist! (skipping)") + log("jedit setup may be incomplete or inconsistent.") } } } -} \ No newline at end of file +} diff --git a/src/jEdit-mmt/src/resources/actions.xml b/src/jEdit-mmt/src/resources/actions.xml index 0b0f280027..45b87bfabf 100644 --- a/src/jEdit-mmt/src/resources/actions.xml +++ b/src/jEdit-mmt/src/resources/actions.xml @@ -1,4 +1,11 @@ + wm.addDockableWindow("mmt-dockable"); @@ -44,4 +51,19 @@ info.kwarc.mmt.jedit.Inserter.insertGSReturn(textArea); + + + jEdit.getPlugin("info.kwarc.mmt.jedit.MMTPlugin", true).editActions().introduceHole(view); + + + + + jEdit.getPlugin("info.kwarc.mmt.jedit.MMTPlugin", true).editActions().showNormalization(view, false); + + + + + jEdit.getPlugin("info.kwarc.mmt.jedit.MMTPlugin", true).editActions().showNormalization(view, true); + + diff --git a/src/jEdit-mmt/src/resources/mmtplugin.props b/src/jEdit-mmt/src/resources/mmtplugin.props index 195282e7e2..32595824c2 100644 --- a/src/jEdit-mmt/src/resources/mmtplugin.props +++ b/src/jEdit-mmt/src/resources/mmtplugin.props @@ -17,7 +17,6 @@ plugin.info.kwarc.mmt.jedit.MMTPlugin.docs=doc.html plugin.info.kwarc.mmt.jedit.MMTPlugin.activate=startup plugin.info.kwarc.mmt.jedit.MMTPlugin.usePluginHome=true -#plugin.info.kwarc.mmt.jedit.MMTPlugin.jars=scala-library.jar scala-parser-combinators.jar scala-reflect.jar scala-xml.jar tiscaf.jar mmt-api.jar lfcatalog.jar mmt-lf.jar mmt-pvs.jar mmt-specware.jar plugin.info.kwarc.mmt.jedit.MMTPlugin.version=1 plugin.info.kwarc.mmt.jedit.MMTPlugin.depend.0=jedit 04.05.00.00 plugin.info.kwarc.mmt.jedit.MMTPlugin.depend.1=plugin errorlist.ErrorListPlugin 1.9 @@ -35,6 +34,9 @@ mmt-buildopen.label=Build open buffers mmt-insert-US.label=Insert Object Delimiter (OD) mmt-insert-RS.label=Insert Declaration Delimiter (DD) mmt-insert-GS.label=Insert Module Delimiter (MD) +mmt-introduce-hole.label=Introduce hole for expected type +mmt-show-normalization.label=Show normalization +mmt-normalize-selection.label=Normalize selection # labels for actions defined in browser.actions.xml mmt-browser-build.label=Build diff --git a/src/jEdit-mmt/src/resources/plugin/keymaps/imported_keys.props b/src/jEdit-mmt/src/resources/plugin/keymaps/imported_keys.props index fedfd3f1fc..081a9031cd 100644 --- a/src/jEdit-mmt/src/resources/plugin/keymaps/imported_keys.props +++ b/src/jEdit-mmt/src/resources/plugin/keymaps/imported_keys.props @@ -1,2 +1,4 @@ # useful key bindings for working with MMT sidekick-complete.shortcut=C+SPACE +mmt-introduce-hole.shortcut=CS+SPACE +mmt-show-normalization.shortcut=CS+n diff --git a/src/latex-mmt/src/info/kwarc/mmt/latex/LatexPresenter.scala b/src/latex-mmt/src/info/kwarc/mmt/latex/LatexPresenter.scala index 183e7e7c4f..de8f1b6298 100644 --- a/src/latex-mmt/src/info/kwarc/mmt/latex/LatexPresenter.scala +++ b/src/latex-mmt/src/info/kwarc/mmt/latex/LatexPresenter.scala @@ -1,627 +1,627 @@ -package info.kwarc.mmt.latex - -import info.kwarc.mmt.api._ -import utils._ -import objects._ -import symbols._ -import modules._ -import documents._ -import opaque._ -import presentation._ -import notations._ -import frontend._ - -class LatexObjectPresenter extends NotationBasedPresenter { - private val unicodeMap = new scala.collection.mutable.HashMap[Char,String]() - private def fillMap(s: String) { - utils.stringToList(s,"\n").foreach {l => - val lT = l.trim - if (!lT.isEmpty || lT.startsWith("//")) { - if (lT.length <= 2 || l(1) != ' ') - throw LocalError(s"illegal line in unicode-latex map: $l") - val c = lT(0) - val s = lT.substring(2) - unicodeMap(c) = s + " " - } - } - } - override def start(args: List[String]) { - val basicmap = MMTSystem.getResourceAsString("latex/unicode-latex-map") - fillMap(basicmap) - args.foreach {a => - fillMap(File.read(File(a))) - } - } - - private def group(body: => Unit)(implicit pc: PresentationContext) {pc.rh.wrap("{","}")(body)} - - override def doToplevel(o: Obj)(body: => Unit)(implicit pc: PresentationContext) { - val tooltip = pc.owner.flatMap {cp => controller.globalLookup.getComponent(cp) match { - case tc : TermContainer => tc.read - case _ => None - }} - tooltip match { - case Some(t) => - pc.rh.wrap(s"\mmt@tooltip{$t}{","}") { - body - } - case None => - body - } - } - override def doIdentifier(p: ContentPath)(implicit pc: PresentationContext) { - pc.rh << s"\\mmt@symref{${p.toPath}}{${p.last.toString}}" - } - override def doVariable(n: LocalName)(implicit pc: PresentationContext) { - pc.rh << s"\\mmt@varref{${n.toPath}}{${n.toPath}}" - } - override def doLiteral(l: OMLITTrait)(implicit pc: PresentationContext) { - pc.rh << s"\\mmt@lit{${l.toString}}" - } - override def doDelimiter(p: GlobalName, d: Delimiter, implicits: List[Cont])(implicit pc: PresentationContext) { - val s = d.text - val sL = if (s.length == 1) unicodeMap.get(s(0)).getOrElse(s) else s - pc.rh << s"\\mmt@symref{${p.toPath}}{$sL}" - } - override def doDelimiter(n: LocalName, d: Delimiter)(implicit pc: PresentationContext) { - pc.rh << s"\\mmt@symref{${n.toPath}}{${d.text}}" - } - override def doSpace(level: Int)(implicit pc: PresentationContext) { - Range(0,level).foreach {_ => pc.rh << "\\,"} - } - override def doBracketedGroup(body: => Unit)(implicit pc: PresentationContext) { - pc.rh.wrap("\\left(\\mmt@group{","}\\right)") { - body - } - } - override def doUnbracketedGroup(body: => Unit)(implicit pc: PresentationContext) { - pc.rh.wrap("\\mmt@group{","}") { - body - } - } - override def doImplicit(body: => Unit)(implicit pc: PresentationContext) { - pc.rh.wrap("\\mmt@implicit{","}") { - body - } - } - override def doInferredType(body: => Unit)(implicit pc: PresentationContext) { - pc.rh.wrap("\\mmt@inferred{","}") { - body - } - } - override def doScript(main: => Unit, sup: Option[Cont], sub: Option[Cont], - over: Option[Cont], under: Option[Cont])(implicit pc: PresentationContext) { - val overunder = over.isDefined || under.isDefined - if (overunder) - pc.rh << "\\stackrel{" - pc.rh.wrap("{", "}"){main} - sup.foreach {s => - pc.rh << "^" - group{s()} - } - sub.foreach {s => - pc.rh << "_" - group{s()} - } - if (overunder) - pc.rh << "}" - over.foreach {s => - pc.rh << "^" - group{s()} - } - under.foreach {s => - pc.rh << "_" - group{s()} - } - } - override def doFraction(above: List[Cont], below: List[Cont], line: Boolean)(implicit pc: PresentationContext) { - val w = if (line) "1pt" else "0pt" - pc.rh << s"\\genfrac{}{}{$w}{0}" - group{doListWithSpace(above, 2)} - group{doListWithSpace(below, 2)} - } -} - - -/** - * replaces mmt with stex declarations, keeps embedded latex as is - */ -class LatexPresenter(oP: ObjectPresenter) extends Presenter(oP) { - def key = "mmt-latex" - - var counter : Int = 1 - override def isApplicable(format : String) = format == "latex" - - def apply(e : StructuralElement, standalone: Boolean = false)(implicit rh : RenderingHandler) { - counter = 1 //resetting counter - e match { - case d: Document => - if (standalone) standaloneHeader - doElement(d) - if (standalone) standaloneFooter - case se => - doElement(se) - } - } - - private def doElement(se: StructuralElement)(implicit rh : RenderingHandler) { - se match { - case d: Document => - d.getDeclarations foreach doElement - case r: NRef => - val e = controller.get(r.target) - doElement(e) - case oe: UnknownOpaqueElement if isApplicable(oe.format) => - val id = "mixref" + counter - counter += 1 - rh.writeln(s"""\\begin{module}[id=$id]""") - rh.writeln(oe.raw.text) - rh.writeln(s"""\\end{module}""") - - case t: DeclaredTheory => - controller.simplifier.apply(t) - rh.writeln(BeginModule(t.parent, t.name).toString()) - doElement(t.asDocument) - rh.writeln(EndModule.toString()) - case PlainInclude(from, to) => - rh.writeln(ImportModule(from).toString) - case c: Constant => - rh.writeln(SymDef(c.home.toMPath, c.name).toString) - case _ => - rh.writeln("%% MMT: skipping " + se.path) - } - } - - private def standaloneHeader(implicit rh : RenderingHandler) { - rh.writeln("""\documentclass{omdoc}""") - rh.writeln("""\begin{document}""") - } - private def standaloneFooter(implicit rh : RenderingHandler) { - rh.writeln("""\end{document}""") - } -} - -/* - * - * // from old LatexPresenter - private def toLatex(tm : Term, scope : MPath, state : LatexState) : String = { - val (notations, extensions) = AbstractObjectParser.getNotations(controller, OMMOD(scope)) - val notationsHash = notations.map(n => (n.name, n)).toMap - val contentRep = toLatex(tm)(new immutable.HashMap[GlobalName,TextNotation], state, None) - val pres = toLatex(tm)(notationsHash, state, None) - s"\\mmtTooltip{$pres}{$contentRep}" - } - - private def loadVars(tm : Term)(implicit state : LatexState) : Unit = { - controller.pragmatic.pragmaticHead(tm) match { - case OMS(p) => - case OMV(v) => - case OMA(f, args) => - loadVars(f) - args.map(loadVars) - case OMBIND(OMS(p), con, body) => con.variables.map(loadVar) - case OMBIND(OMA(OMS(p), args), con, body) => con.variables.map(loadVar) - case t => throw LatexError("Invalid term in load Vars : " + t.toString) - } - } - - private def loadVar(v : VarDecl)(implicit state : LatexState) = { - state.addVar(v.name) - } - - - private def wrapInferredArgs(s : String, args : List[Term]) - (implicit notations : Map[GlobalName,TextNotation], state : LatexState, parentNot : Option[TextNotation]) : String = { - val inferred = args filter {t => SourceRef.get(t) match { - case None => true //inferred - case _ => false - }} - val infS = inferred.map(toLatex).mkString(" ") - s"\\mmtinferredargs{$s}{$infS}" - - } - - private def toLatex(tm : Term)(implicit notations : Map[GlobalName,TextNotation], state : LatexState, parentNot : Option[TextNotation]) : String = { - controller.pragmatic.pragmaticHead(tm) match { - case OMS(p) => "\\" + Utils.latexName(p) - case OMA(OMS(p), args) => notations.get(p) match { - case Some(not) => - val markers = not.parsingMarkers - val sqargs = markers collect { - case SeqArg(n,sep) => (n,sep) - } - sqargs match { - case Nil => - val str = toLatex(OMS(p)) + args.map(t => toLatex(t)(notations, state, Some(not))).mkString("{","}{","}") - parentNot match { - case Some(n) if n == not => "(" + str + ")" - case _ => str - } - case hd :: Nil => //one seq arg, must detect corresponding content arguments - val pos = hd._1 - val sep = hd._2 - val arity = not.arity.length - val (begin,rest) = args.splitAt(pos - 1) - val (seq, end) = rest.splitAt(args.length - arity) - val beginS = begin.map(toLatex).mkString("{","}{","}") - val seqS = s"{\\mmtseq{${seq.map(toLatex).mkString(sep.s)}}}" - val endS = begin.map(toLatex).mkString("{","}{","}") - toLatex(OMS(p)) + beginS + seqS + endS - case _ => throw LatexError("Multiple sequence arguments in the same notation not supported yet") - } - case None => "(" + p.last + "\\;" + args.map(toLatex).mkString("\\:") + ")" - } - case OMBIND(b, con, body) => controller.pragmatic.pragmaticHead(b) match { - //case args = Nil with OMS(p) - case OMA(OMS(p), args) => notations.get(p) match { - case Some(not) => - val argsS = args match { - case Nil => "" - case _ => args.map(toLatex).mkString("{","}{","}") - } - not.parsingMarkers find { - case Var(_,_,Some(sep)) => true - case _ => false - } match { - case Some(Var(_,_,Some(sep))) => - val vars = con.variables.map(vToLatex).mkString(sep.s) - s"${toLatex(OMS(p))}$argsS{$vars}{${toLatex(body)}}" - case _ => - assert(con.variables.length == 1, "expected one variable argument") - s"${toLatex(OMS(p))}$argsS{${vToLatex(con.variables.head)}}{${toLatex(body)}}" - } - case None => - assert(con.variables.length == 1, "expected one variable argument") - val v = con.variables.head - s"(${p.last}\\;${vToLatex(v)}\\, . \\, ${toLatex(body)}" - } - } - case OMA(OMV(v), args) => s"${toLatex(OMV(v))} ${args.map(toLatex).mkString("{ }")}" - case OMV(n) => try { - s"\\mmtboundvarref{$n}{${state.resolveVar(n)}}" - } catch { - case e : Exception => n.toString - } - case OMA(f, args) => s"(${toLatex(f)}\\;${args.map(toLatex).mkString("\\:")})" - case t => throw LatexError("Term cannot be converted to latex : " + t.toString) - } - } - - def vToLatex(v : VarDecl)(implicit notations : Map[GlobalName,TextNotation], state : LatexState, parentNot : Option[TextNotation]) : String = { - val vname = try { - val id = state.resolveVar(v.name) - s"\\mmtboundvar{${v.name}}{$id}" - } catch { - case e : Exception => v.name.toString - } - v match { - case VarDecl(a, Some(tp), None) => - SourceRef.get(tp) match { - case None => //inferred - s"\\mmtinferredtype{$vname}{${tp.toString}}" - case _ => //already typed - s"\\mmttype{$vname}{${toLatex(tp)}}" - } - case _ => vname - } - } - - - /** Server */ - def isApplicable(uriComp : List[String]) = { - uriComp.head == ":latex" - } - - def apply(uriComps: List[String], query: String, body : Body): HLet = { - try { - uriComps match { - case "postdecl" :: _ => PostDeclResponse - case "getobjpres" :: _ => GetObjPresResponse - case "context" :: _ => ContextResponse - case _ => errorResponse("Invalid request : " + uriComps.mkString("/")) - } - } catch { - case e : LatexError => errorResponse(e.text) - case e : Error => errorResponse(e.longMsg) - case e : Exception => errorResponse("Exception occured : " + e.getMessage()) - } - } - - private def ContextResponse : HLet = new HLet { - def aact(tk : HTalk)(implicit ec : ExecutionContext) = try { - val jobname = tk.req.header("jobname").getOrElse(throw LatexError("found no jobname for request")) - val request = tk.req.header("request").getOrElse(throw LatexError("found no context update request")) - val text = bodyAsString(tk) - var resp = "" - if (!states.isDefinedAt(jobname)) { - throw LatexError(s"given jobname: $jobname not active") - } else { - val state = states(jobname) - request match { - case "clear" => state.clearContext() - case "new" => state.addContext() - case "addvar" => text.split(":").toList match { - case name :: tpS :: Nil => - val vname = LocalName(name) - val id = state.addVar(vname) - resp = s"\\mmtboundvar{$vname}{$id}" - log("currentContext :" + state.context) - val pu = new parser.ParsingUnit(parser.SourceRef(state.mod.doc.uri,SourceRegion.ofString(tpS)), OMMOD(state.mod), state.context, tpS) - val tp = controller.termParser(pu, err => log(err)) - val v = VarDecl(LocalName(name), Some(tp), None) - state.addVar(v) - case _ => throw LatexError(s"invalid var: $text") - } - } - - Server.TextResponse(resp).aact(tk) - } - } catch { - case e : LatexError => errorResponse(e.text).aact(tk) - case e : Error => errorResponse(e.shortMsg).aact(tk) - case e : Exception => errorResponse("Exception occured : " + e.getMessage()).aact(tk) - } - } - - private def PostDeclResponse : HLet = new HLet { - def aact(tk : HTalk)(implicit ec : ExecutionContext) = try { - val text = bodyAsString(tk) - val jobname = tk.req.header("jobname").getOrElse(throw LatexError("found no jobname for request")) - val dpathS = tk.req.header("dpath").getOrElse(throw LatexError("found no dpath")) - val notPresS = tk.req.header("pres").getOrElse("") - - - val dpath = DPath(URI(dpathS)) - log("received : " + jobname + " and " + dpathS + " : " + text) - if (!states.isDefinedAt(jobname)) { - val state = new LatexState(dpath, controller) - state.setParserState(text) - if(!notPresS.isEmpty) - state.notationQueue.enqueue(notPresS) - states(jobname) = state - val thread = new Thread(new Runnable { - def run() { - state.parser(state.parserState, dpath) - } - }) - thread.start - state.waitDone - val resp = state.parser.addedMacros.mkString("\n") - state.parser.addedMacros = Nil - Server.TextResponse(resp).aact(tk) - } else { - val ltxState = states(jobname) - if(!notPresS.isEmpty) - ltxState.notationQueue.enqueue(notPresS) - ltxState.setParserState(text) - ltxState.waitDone - val resp = ltxState.parser.addedMacros.mkString("\n") - log("RESP :" + resp + ": END RESP") - ltxState.parser.addedMacros = Nil - Server.TextResponse(resp).aact(tk) - } - } catch { - case e : LatexError => errorResponse(e.text).aact(tk) - case e : Error => errorResponse(e.shortMsg).aact(tk) - case e : Exception => errorResponse("Exception occured : " + e.getMessage()).aact(tk) - } - } - - - private def GetObjPresResponse : HLet = new HLet { - def aact(tk : HTalk)(implicit ec : ExecutionContext) = try { - val text = bodyAsString(tk) - val jobname = tk.req.header("jobname").getOrElse(throw LatexError("found no jobname in request")) - val state = states(jobname) - val home = tk.req.header("home").map(Path.parse).getOrElse { - state.mod - } - - log("received get : " + text) - - home match { - case mod : MPath => - val pu = new parser.ParsingUnit(parser.SourceRef(mod.doc.uri,SourceRegion.ofString(text)), objects.OMMOD(mod), state.context, text) - val tm = controller.termParser(pu, err => log(err)) - val (unknowns,tmU) = parser.AbstractObjectParser.splitOffUnknowns(tm) - val etp = LocalName("expected_type") - val oc = new Solver(controller, OMMOD(mod), unknowns ++ VarDecl(etp, None, None)) - val j = Typing(Stack(mod, state.context), tmU, OMV(etp)) - oc(j) - oc.getSolution match { - case Some(sub) => - val tmR = tmU ^ sub - val tmRU = controller.uom.simplify(tmR, OMMOD(mod)) -// val tmRS = Utils.rreduce(tmRU) - log("Orginal term : " + tmU.toString) - log("Reduced Term : " + tmRU.toString) - loadVars(tmRU)(state) - val resp = toLatex(tmRU, mod, state) - log("Sending ResponseRS" + resp) - Server.TextResponse(resp).aact(tk) - case None => - loadVars(tmU)(state) - val resp = toLatex(tmU,mod, state) - log("Sending ResponseU" + resp) - - // throw LatexError("type reconstruction failed") - Server.TextResponse(resp).aact(tk) //until things are stable sending non-reconstructed term - } - case _ => throw LatexError("support for non-module paths not implemented yet") - } - } catch { - case e : LatexError => errorResponse(e.text).aact(tk) - case e : Error => errorResponse(e.shortMsg).aact(tk) - case e : Exception => errorResponse("Exception occured : " + e.getMessage()).aact(tk) - } - } - - private def sanitizeInput(text : String) : String = { - text.replaceAllLiterally("\\ldots", "…") - } - - private def bodyAsString(tk: HTalk): String = { - val bodyArray: Array[Byte] = tk.req.octets.getOrElse(throw LatexError("no body found")) - val text = new String(bodyArray, "UTF-8") - sanitizeInput(text) - } - - private def errorResponse(text : String) : HLet = { - Server.TextResponse(s"\\mmtError{$text}") - } - - -} - - -class LatexStructureParser(ltxState : LatexState, controller : Controller) extends StructureAndObjectParser(controller) { - var addedMacros : List[String] = Nil - def getSourceFile(state : ParserState) : String = { - val fs = state.container.uri.pathAsString - val pos = fs.lastIndexOf('.') - "run:./" + fs.substring(0,pos) + ".pdf" - } - - override def seCont(se: StructuralElement)(implicit state: ParserState) { - log(se.toString) - SourceRef.update(se, SourceRef(state.container.uri,currentSourceRegion)) - val source = getSourceFile(state) - se match { - case c : Constant => - if (!ltxState.notationQueue.isEmpty) { - val defaultNot = TextNotation.parse(ltxState.notationQueue.dequeue(), c.path) - addedMacros ::= makeMacro(defaultNot, source) - } else {//no explicit presentation notation - c.not match { - case None => - val m1 = s"\\gdef\\${Utils.latexName(c.path)}{${wrapLink(c.name.toString,c.path,source)}}" - val m2 = s"\\hyperdef{mmt}{${c.path}}{}" - addedMacros ::= (m1 + "\n" + m2) - case Some(notation) => addedMacros ::= makeMacro(notation, source) - } - } - case m : modules.Module => ltxState.mod = m.path - case _ => - } - controller.add(se) - } - - private def makeMacro(marker : Marker, mmtName : GlobalName, source : String) : String = marker match { - case Delim(str) => wrapLink(str, mmtName, source) - case Arg(i) => s"#${i.abs}" - case SeqArg(i,d) => s"\\mmtseq{#${i.abs}}{${makeMacro(d, mmtName, source)}}" - case Var(i, t, sO) => s"#${i.abs}" //TODO - case p : PlaceholderDelimiter => throw LatexError("Marker PlaceholderDelimiter shouldn't occur in Notations") - } - - def wrapLink(del : String, path : GlobalName, source : String) : String = del match { - case "_" => "_" - case "^" => "^" - case "{" => "{" - case "}" => "}" - case str => s"\\mmtlink[$source]{$str}{${path.toPath}}" - } - - - def makeMacro(not : TextNotation, source : String) : String = { - val mmtName = not.name - val markers = not.parsingMarkers - val body = markers.map(makeMacro(_, mmtName, source)).mkString(" ") - val label = s"\\hyperdef{mmt}{${mmtName.toPath}}{}" - val args = (1 to not.arity.length).map(i => s"#$i").mkString("") - s"\\gdef\\${Utils.latexName(mmtName)}$args{$body}\n $label\n" - } - -} - -import info.kwarc.mmt.lf._ - -object Utils { - private val sep = "" - def latexName(mmtName : GlobalName) : String = "mmt" + sep + mmtName.module.toMPath.last + sep + mmtName.last -// def reduce(t: Term) : Term = { -// t match { -// case OMA(OMS(Apply.path), OMBIND(OMS(Lambda.path), con, body) :: OMV(n) :: rest) => -// val names = con.variables.map(_.name) -// if (names.head == n) { -// rest match { -// case Nil => reduce(body) -// case _ => reduce(OMA(OMS(Apply.path), body :: rest)) -// } -// } else -// OMA(OMS(Apply.path), OMBIND(OMS(Lambda.path), reduceCon(con), reduce(body)) :: OMV(n) :: Nil) -// // case OMA(OMS(Apply.path), hd :: rest) => reduce(OMA(hd, rest)) -// case OMA(f, args) => -// OMA(reduce(f), args map reduce).from(t) -// case OMBIND(b,con, s) => OMBIND(reduce(b), reduceCon(con), reduce(s)).from(t) -// case _ => t -// } -// } -// -// def reduceCon(con : Context) : Context = { -// val nvars = con.variables map { -// case VarDecl(n, Some(tp), df, _*) => VarDecl(n, Some(reduce(tp)), df) -// case v => v -// } -// Context(nvars : _*) -// } - -} - -*/ - -/* -case class LatexError(val text : String) extends Error(text) - -class LatexState(val dpath : DPath, controller : Controller) { - val dictionary = new mutable.HashMap[LocalName, String] // ?needed - - val parser = new LatexStructureParser(this, controller) - - def context = varContexts match { - case Nil => Context() - case hd :: Nil => hd - case l => l.reduceLeft((x,y) => x ++ y) - } - - var varContexts : List[Context] = Nil - def addContext(con : Context = Context()) = varContexts ::= con - def addVar(v : VarDecl) = varContexts = (varContexts.head ++ v) :: varContexts.tail - - def clearContext() = varContexts = varContexts.tail - - var mod : MPath = null //current module - - val seqReader = new SeqBufReader - val parserState = new ParserState(new Reader(seqReader), dpath) - - var notationQueue = new mutable.Queue[String] - - def setParserState(text : String) { - seqReader.appendLine(text) - } - - val varIds = new mutable.HashMap[LocalName,Int] - - var currentId = 0 - def getFreshId = { - currentId += 1 - currentId - } - - def addVar(name : LocalName) = { - varIds(name) = getFreshId - resolveVar(name) - } - - def resolveVar(name : LocalName) = varIds(name) - - def waitDone() { - - while(!seqReader.isDone) { - Thread.sleep(10) - } - Thread.sleep(100) - } -} -* */ +package info.kwarc.mmt.latex + +import info.kwarc.mmt.api._ +import utils._ +import objects._ +import symbols._ +import modules._ +import documents._ +import opaque._ +import presentation._ +import notations._ +import frontend._ + +class LatexObjectPresenter extends NotationBasedPresenter { + private val unicodeMap = new scala.collection.mutable.HashMap[Char,String]() + private def fillMap(s: String) { + utils.stringToList(s,"\n").foreach {l => + val lT = l.trim + if (!lT.isEmpty || lT.startsWith("//")) { + if (lT.length <= 2 || l(1) != ' ') + throw LocalError(s"illegal line in unicode-latex map: $l") + val c = lT(0) + val s = lT.substring(2) + unicodeMap(c) = s + " " + } + } + } + override def start(args: List[String]) { + val basicmap = MMTSystem.getResourceAsString("latex/unicode-latex-map") + fillMap(basicmap) + args.foreach {a => + fillMap(File.read(File(a))) + } + } + + private def group(body: => Unit)(implicit pc: PresentationContext) {pc.rh.wrap("{","}")(body)} + + override def doToplevel(o: Obj)(body: => Unit)(implicit pc: PresentationContext) { + val tooltip = pc.owner.flatMap {cp => controller.globalLookup.getComponent(cp) match { + case tc : TermContainer => tc.read + case _ => None + }} + tooltip match { + case Some(t) => + pc.rh.wrap(s"\mmt@tooltip{$t}{","}") { + body + } + case None => + body + } + } + override def doIdentifier(p: ContentPath)(implicit pc: PresentationContext) { + pc.rh << s"\\mmt@symref{${p.toPath}}{${p.last.toString}}" + } + override def doVariable(n: LocalName)(implicit pc: PresentationContext) { + pc.rh << s"\\mmt@varref{${n.toPath}}{${n.toPath}}" + } + override def doLiteral(l: OMLITTrait)(implicit pc: PresentationContext) { + pc.rh << s"\\mmt@lit{${l.toString}}" + } + override def doDelimiter(p: GlobalName, d: Delimiter, implicits: List[Cont])(implicit pc: PresentationContext) { + val s = d.text + val sL = if (s.length == 1) unicodeMap.get(s(0)).getOrElse(s) else s + pc.rh << s"\\mmt@symref{${p.toPath}}{$sL}" + } + override def doDelimiter(n: LocalName, d: Delimiter)(implicit pc: PresentationContext) { + pc.rh << s"\\mmt@symref{${n.toPath}}{${d.text}}" + } + override def doSpace(level: Int)(implicit pc: PresentationContext) { + Range(0,level).foreach {_ => pc.rh << "\\,"} + } + override def doBracketedGroup(body: => Unit)(implicit pc: PresentationContext) { + pc.rh.wrap("\\left(\\mmt@group{","}\\right)") { + body + } + } + override def doUnbracketedGroup(body: => Unit)(implicit pc: PresentationContext) { + pc.rh.wrap("\\mmt@group{","}") { + body + } + } + override def doImplicit(body: => Unit)(implicit pc: PresentationContext) { + pc.rh.wrap("\\mmt@implicit{","}") { + body + } + } + override def doInferredType(body: => Unit)(implicit pc: PresentationContext) { + pc.rh.wrap("\\mmt@inferred{","}") { + body + } + } + override def doScript(main: => Unit, sup: Option[Cont], sub: Option[Cont], + over: Option[Cont], under: Option[Cont])(implicit pc: PresentationContext) { + val overunder = over.isDefined || under.isDefined + if (overunder) + pc.rh << "\\stackrel{" + pc.rh.wrap("{", "}"){main} + sup.foreach {s => + pc.rh << "^" + group{s()} + } + sub.foreach {s => + pc.rh << "_" + group{s()} + } + if (overunder) + pc.rh << "}" + over.foreach {s => + pc.rh << "^" + group{s()} + } + under.foreach {s => + pc.rh << "_" + group{s()} + } + } + override def doFraction(above: List[Cont], below: List[Cont], line: Boolean)(implicit pc: PresentationContext) { + val w = if (line) "1pt" else "0pt" + pc.rh << s"\\genfrac{}{}{$w}{0}" + group{doListWithSpace(above, 2)} + group{doListWithSpace(below, 2)} + } +} + + +/** + * replaces mmt with stex declarations, keeps embedded latex as is + */ +class LatexPresenter(oP: ObjectPresenter) extends Presenter(oP) { + def key = "mmt-latex" + + var counter : Int = 1 + override def isApplicable(format : String) = format == "latex" + + def apply(e : StructuralElement, standalone: Boolean = false)(implicit rh : RenderingHandler) { + counter = 1 //resetting counter + e match { + case d: Document => + if (standalone) standaloneHeader + doElement(d) + if (standalone) standaloneFooter + case se => + doElement(se) + } + } + + private def doElement(se: StructuralElement)(implicit rh : RenderingHandler) { + se match { + case d: Document => + d.getDeclarations foreach doElement + case r: NRef => + val e = controller.get(r.target) + doElement(e) + case oe: UnknownOpaqueElement if isApplicable(oe.format) => + val id = "mixref" + counter + counter += 1 + rh.writeln(s"""\\begin{module}[id=$id]""") + rh.writeln(oe.raw.text) + rh.writeln(s"""\\end{module}""") + + case t: DeclaredTheory => + controller.simplifier.apply(t) + rh.writeln(BeginModule(t.parent, t.name).toString()) + doElement(t.asDocument) + rh.writeln(EndModule.toString()) + case PlainInclude(from, to) => + rh.writeln(ImportModule(from).toString) + case c: Constant => + rh.writeln(SymDef(c.home.toMPath, c.name).toString) + case _ => + rh.writeln("%% MMT: skipping " + se.path) + } + } + + private def standaloneHeader(implicit rh : RenderingHandler) { + rh.writeln("""\documentclass{omdoc}""") + rh.writeln("""\begin{document}""") + } + private def standaloneFooter(implicit rh : RenderingHandler) { + rh.writeln("""\end{document}""") + } +} + +/* + * + * // from old LatexPresenter + private def toLatex(tm : Term, scope : MPath, state : LatexState) : String = { + val (notations, extensions) = AbstractObjectParser.getNotations(controller, OMMOD(scope)) + val notationsHash = notations.map(n => (n.name, n)).toMap + val contentRep = toLatex(tm)(new immutable.HashMap[GlobalName,TextNotation], state, None) + val pres = toLatex(tm)(notationsHash, state, None) + s"\\mmtTooltip{$pres}{$contentRep}" + } + + private def loadVars(tm : Term)(implicit state : LatexState) : Unit = { + controller.pragmatic.pragmaticHead(tm) match { + case OMS(p) => + case OMV(v) => + case OMA(f, args) => + loadVars(f) + args.map(loadVars) + case OMBIND(OMS(p), con, body) => con.variables.map(loadVar) + case OMBIND(OMA(OMS(p), args), con, body) => con.variables.map(loadVar) + case t => throw LatexError("Invalid term in load Vars : " + t.toString) + } + } + + private def loadVar(v : VarDecl)(implicit state : LatexState) = { + state.addVar(v.name) + } + + + private def wrapInferredArgs(s : String, args : List[Term]) + (implicit notations : Map[GlobalName,TextNotation], state : LatexState, parentNot : Option[TextNotation]) : String = { + val inferred = args filter {t => SourceRef.get(t) match { + case None => true //inferred + case _ => false + }} + val infS = inferred.map(toLatex).mkString(" ") + s"\\mmtinferredargs{$s}{$infS}" + + } + + private def toLatex(tm : Term)(implicit notations : Map[GlobalName,TextNotation], state : LatexState, parentNot : Option[TextNotation]) : String = { + controller.pragmatic.pragmaticHead(tm) match { + case OMS(p) => "\\" + Utils.latexName(p) + case OMA(OMS(p), args) => notations.get(p) match { + case Some(not) => + val markers = not.parsingMarkers + val sqargs = markers collect { + case SeqArg(n,sep) => (n,sep) + } + sqargs match { + case Nil => + val str = toLatex(OMS(p)) + args.map(t => toLatex(t)(notations, state, Some(not))).mkString("{","}{","}") + parentNot match { + case Some(n) if n == not => "(" + str + ")" + case _ => str + } + case hd :: Nil => //one seq arg, must detect corresponding content arguments + val pos = hd._1 + val sep = hd._2 + val arity = not.arity.length + val (begin,rest) = args.splitAt(pos - 1) + val (seq, end) = rest.splitAt(args.length - arity) + val beginS = begin.map(toLatex).mkString("{","}{","}") + val seqS = s"{\\mmtseq{${seq.map(toLatex).mkString(sep.s)}}}" + val endS = begin.map(toLatex).mkString("{","}{","}") + toLatex(OMS(p)) + beginS + seqS + endS + case _ => throw LatexError("Multiple sequence arguments in the same notation not supported yet") + } + case None => "(" + p.last + "\\;" + args.map(toLatex).mkString("\\:") + ")" + } + case OMBIND(b, con, body) => controller.pragmatic.pragmaticHead(b) match { + //case args = Nil with OMS(p) + case OMA(OMS(p), args) => notations.get(p) match { + case Some(not) => + val argsS = args match { + case Nil => "" + case _ => args.map(toLatex).mkString("{","}{","}") + } + not.parsingMarkers find { + case Var(_,_,Some(sep)) => true + case _ => false + } match { + case Some(Var(_,_,Some(sep))) => + val vars = con.variables.map(vToLatex).mkString(sep.s) + s"${toLatex(OMS(p))}$argsS{$vars}{${toLatex(body)}}" + case _ => + assert(con.variables.length == 1, "expected one variable argument") + s"${toLatex(OMS(p))}$argsS{${vToLatex(con.variables.head)}}{${toLatex(body)}}" + } + case None => + assert(con.variables.length == 1, "expected one variable argument") + val v = con.variables.head + s"(${p.last}\\;${vToLatex(v)}\\, . \\, ${toLatex(body)}" + } + } + case OMA(OMV(v), args) => s"${toLatex(OMV(v))} ${args.map(toLatex).mkString("{ }")}" + case OMV(n) => try { + s"\\mmtboundvarref{$n}{${state.resolveVar(n)}}" + } catch { + case e : Exception => n.toString + } + case OMA(f, args) => s"(${toLatex(f)}\\;${args.map(toLatex).mkString("\\:")})" + case t => throw LatexError("Term cannot be converted to latex : " + t.toString) + } + } + + def vToLatex(v : VarDecl)(implicit notations : Map[GlobalName,TextNotation], state : LatexState, parentNot : Option[TextNotation]) : String = { + val vname = try { + val id = state.resolveVar(v.name) + s"\\mmtboundvar{${v.name}}{$id}" + } catch { + case e : Exception => v.name.toString + } + v match { + case VarDecl(a, Some(tp), None) => + SourceRef.get(tp) match { + case None => //inferred + s"\\mmtinferredtype{$vname}{${tp.toString}}" + case _ => //already typed + s"\\mmttype{$vname}{${toLatex(tp)}}" + } + case _ => vname + } + } + + + /** Server */ + def isApplicable(uriComp : List[String]) = { + uriComp.head == ":latex" + } + + def apply(uriComps: List[String], query: String, body : Body): HLet = { + try { + uriComps match { + case "postdecl" :: _ => PostDeclResponse + case "getobjpres" :: _ => GetObjPresResponse + case "context" :: _ => ContextResponse + case _ => errorResponse("Invalid request : " + uriComps.mkString("/")) + } + } catch { + case e : LatexError => errorResponse(e.text) + case e : Error => errorResponse(e.longMsg) + case e : Exception => errorResponse("Exception occured : " + e.getMessage()) + } + } + + private def ContextResponse : HLet = new HLet { + def aact(tk : HTalk)(implicit ec : ExecutionContext) = try { + val jobname = tk.req.header("jobname").getOrElse(throw LatexError("found no jobname for request")) + val request = tk.req.header("request").getOrElse(throw LatexError("found no context update request")) + val text = bodyAsString(tk) + var resp = "" + if (!states.isDefinedAt(jobname)) { + throw LatexError(s"given jobname: $jobname not active") + } else { + val state = states(jobname) + request match { + case "clear" => state.clearContext() + case "new" => state.addContext() + case "addvar" => text.split(":").toList match { + case name :: tpS :: Nil => + val vname = LocalName(name) + val id = state.addVar(vname) + resp = s"\\mmtboundvar{$vname}{$id}" + log("currentContext :" + state.context) + val pu = new parser.ParsingUnit(parser.SourceRef(state.mod.doc.uri,SourceRegion.ofString(tpS)), OMMOD(state.mod), state.context, tpS) + val tp = controller.termParser(pu, err => log(err)) + val v = VarDecl(LocalName(name), Some(tp), None) + state.addVar(v) + case _ => throw LatexError(s"invalid var: $text") + } + } + + Server.TextResponse(resp).aact(tk) + } + } catch { + case e : LatexError => errorResponse(e.text).aact(tk) + case e : Error => errorResponse(e.shortMsg).aact(tk) + case e : Exception => errorResponse("Exception occured : " + e.getMessage()).aact(tk) + } + } + + private def PostDeclResponse : HLet = new HLet { + def aact(tk : HTalk)(implicit ec : ExecutionContext) = try { + val text = bodyAsString(tk) + val jobname = tk.req.header("jobname").getOrElse(throw LatexError("found no jobname for request")) + val dpathS = tk.req.header("dpath").getOrElse(throw LatexError("found no dpath")) + val notPresS = tk.req.header("pres").getOrElse("") + + + val dpath = DPath(URI(dpathS)) + log("received : " + jobname + " and " + dpathS + " : " + text) + if (!states.isDefinedAt(jobname)) { + val state = new LatexState(dpath, controller) + state.setParserState(text) + if(!notPresS.isEmpty) + state.notationQueue.enqueue(notPresS) + states(jobname) = state + val thread = new Thread(new Runnable { + def run() { + state.parser(state.parserState, dpath) + } + }) + thread.start + state.waitDone + val resp = state.parser.addedMacros.mkString("\n") + state.parser.addedMacros = Nil + Server.TextResponse(resp).aact(tk) + } else { + val ltxState = states(jobname) + if(!notPresS.isEmpty) + ltxState.notationQueue.enqueue(notPresS) + ltxState.setParserState(text) + ltxState.waitDone + val resp = ltxState.parser.addedMacros.mkString("\n") + log("RESP :" + resp + ": END RESP") + ltxState.parser.addedMacros = Nil + Server.TextResponse(resp).aact(tk) + } + } catch { + case e : LatexError => errorResponse(e.text).aact(tk) + case e : Error => errorResponse(e.shortMsg).aact(tk) + case e : Exception => errorResponse("Exception occured : " + e.getMessage()).aact(tk) + } + } + + + private def GetObjPresResponse : HLet = new HLet { + def aact(tk : HTalk)(implicit ec : ExecutionContext) = try { + val text = bodyAsString(tk) + val jobname = tk.req.header("jobname").getOrElse(throw LatexError("found no jobname in request")) + val state = states(jobname) + val home = tk.req.header("home").map(Path.parse).getOrElse { + state.mod + } + + log("received get : " + text) + + home match { + case mod : MPath => + val pu = new parser.ParsingUnit(parser.SourceRef(mod.doc.uri,SourceRegion.ofString(text)), objects.OMMOD(mod), state.context, text) + val tm = controller.termParser(pu, err => log(err)) + val (unknowns,tmU) = parser.AbstractObjectParser.splitOffUnknowns(tm) + val etp = LocalName("expected_type") + val oc = new Solver(controller, OMMOD(mod), unknowns ++ VarDecl(etp, None, None)) + val j = Typing(Stack(mod, state.context), tmU, OMV(etp)) + oc(j) + oc.getSolution match { + case Some(sub) => + val tmR = tmU ^ sub + val tmRU = controller.uom.simplify(tmR, OMMOD(mod)) +// val tmRS = Utils.rreduce(tmRU) + log("Orginal term : " + tmU.toString) + log("Reduced Term : " + tmRU.toString) + loadVars(tmRU)(state) + val resp = toLatex(tmRU, mod, state) + log("Sending ResponseRS" + resp) + Server.TextResponse(resp).aact(tk) + case None => + loadVars(tmU)(state) + val resp = toLatex(tmU,mod, state) + log("Sending ResponseU" + resp) + + // throw LatexError("type reconstruction failed") + Server.TextResponse(resp).aact(tk) //until things are stable sending non-reconstructed term + } + case _ => throw LatexError("support for non-module paths not implemented yet") + } + } catch { + case e : LatexError => errorResponse(e.text).aact(tk) + case e : Error => errorResponse(e.shortMsg).aact(tk) + case e : Exception => errorResponse("Exception occured : " + e.getMessage()).aact(tk) + } + } + + private def sanitizeInput(text : String) : String = { + text.replaceAllLiterally("\\ldots", "…") + } + + private def bodyAsString(tk: HTalk): String = { + val bodyArray: Array[Byte] = tk.req.octets.getOrElse(throw LatexError("no body found")) + val text = new String(bodyArray, "UTF-8") + sanitizeInput(text) + } + + private def errorResponse(text : String) : HLet = { + Server.TextResponse(s"\\mmtError{$text}") + } + + +} + + +class LatexStructureParser(ltxState : LatexState, controller : Controller) extends StructureAndObjectParser(controller) { + var addedMacros : List[String] = Nil + def getSourceFile(state : ParserState) : String = { + val fs = state.container.uri.pathAsString + val pos = fs.lastIndexOf('.') + "run:./" + fs.substring(0,pos) + ".pdf" + } + + override def seCont(se: StructuralElement)(implicit state: ParserState) { + log(se.toString) + SourceRef.update(se, SourceRef(state.container.uri,currentSourceRegion)) + val source = getSourceFile(state) + se match { + case c : Constant => + if (!ltxState.notationQueue.isEmpty) { + val defaultNot = TextNotation.parse(ltxState.notationQueue.dequeue(), c.path) + addedMacros ::= makeMacro(defaultNot, source) + } else {//no explicit presentation notation + c.not match { + case None => + val m1 = s"\\gdef\\${Utils.latexName(c.path)}{${wrapLink(c.name.toString,c.path,source)}}" + val m2 = s"\\hyperdef{mmt}{${c.path}}{}" + addedMacros ::= (m1 + "\n" + m2) + case Some(notation) => addedMacros ::= makeMacro(notation, source) + } + } + case m : modules.Module => ltxState.mod = m.path + case _ => + } + controller.add(se) + } + + private def makeMacro(marker : Marker, mmtName : GlobalName, source : String) : String = marker match { + case Delim(str) => wrapLink(str, mmtName, source) + case Arg(i) => s"#${i.abs}" + case SeqArg(i,d) => s"\\mmtseq{#${i.abs}}{${makeMacro(d, mmtName, source)}}" + case Var(i, t, sO) => s"#${i.abs}" //TODO + case p : PlaceholderDelimiter => throw LatexError("Marker PlaceholderDelimiter shouldn't occur in Notations") + } + + def wrapLink(del : String, path : GlobalName, source : String) : String = del match { + case "_" => "_" + case "^" => "^" + case "{" => "{" + case "}" => "}" + case str => s"\\mmtlink[$source]{$str}{${path.toPath}}" + } + + + def makeMacro(not : TextNotation, source : String) : String = { + val mmtName = not.name + val markers = not.parsingMarkers + val body = markers.map(makeMacro(_, mmtName, source)).mkString(" ") + val label = s"\\hyperdef{mmt}{${mmtName.toPath}}{}" + val args = (1 to not.arity.length).map(i => s"#$i").mkString("") + s"\\gdef\\${Utils.latexName(mmtName)}$args{$body}\n $label\n" + } + +} + +import info.kwarc.mmt.lf._ + +object Utils { + private val sep = "" + def latexName(mmtName : GlobalName) : String = "mmt" + sep + mmtName.module.toMPath.last + sep + mmtName.last +// def reduce(t: Term) : Term = { +// t match { +// case OMA(OMS(Apply.path), OMBIND(OMS(Lambda.path), con, body) :: OMV(n) :: rest) => +// val names = con.variables.map(_.name) +// if (names.head == n) { +// rest match { +// case Nil => reduce(body) +// case _ => reduce(OMA(OMS(Apply.path), body :: rest)) +// } +// } else +// OMA(OMS(Apply.path), OMBIND(OMS(Lambda.path), reduceCon(con), reduce(body)) :: OMV(n) :: Nil) +// // case OMA(OMS(Apply.path), hd :: rest) => reduce(OMA(hd, rest)) +// case OMA(f, args) => +// OMA(reduce(f), args map reduce).from(t) +// case OMBIND(b,con, s) => OMBIND(reduce(b), reduceCon(con), reduce(s)).from(t) +// case _ => t +// } +// } +// +// def reduceCon(con : Context) : Context = { +// val nvars = con.variables map { +// case VarDecl(n, Some(tp), df, _*) => VarDecl(n, Some(reduce(tp)), df) +// case v => v +// } +// Context(nvars : _*) +// } + +} + +*/ + +/* +case class LatexError(val text : String) extends Error(text) + +class LatexState(val dpath : DPath, controller : Controller) { + val dictionary = new mutable.HashMap[LocalName, String] // ?needed + + val parser = new LatexStructureParser(this, controller) + + def context = varContexts match { + case Nil => Context() + case hd :: Nil => hd + case l => l.reduceLeft((x,y) => x ++ y) + } + + var varContexts : List[Context] = Nil + def addContext(con : Context = Context()) = varContexts ::= con + def addVar(v : VarDecl) = varContexts = (varContexts.head ++ v) :: varContexts.tail + + def clearContext() = varContexts = varContexts.tail + + var mod : MPath = null //current module + + val seqReader = new SeqBufReader + val parserState = new ParserState(new Reader(seqReader), dpath) + + var notationQueue = new mutable.Queue[String] + + def setParserState(text : String) { + seqReader.appendLine(text) + } + + val varIds = new mutable.HashMap[LocalName,Int] + + var currentId = 0 + def getFreshId = { + currentId += 1 + currentId + } + + def addVar(name : LocalName) = { + varIds(name) = getFreshId + resolveVar(name) + } + + def resolveVar(name : LocalName) = varIds(name) + + def waitDone() { + + while(!seqReader.isDone) { + Thread.sleep(10) + } + Thread.sleep(100) + } +} +* */ diff --git a/src/latex-mmt/src/info/kwarc/mmt/latex/MMTTeX.scala b/src/latex-mmt/src/info/kwarc/mmt/latex/MMTTeX.scala index 1da187c37c..6ee0dd4b18 100644 --- a/src/latex-mmt/src/info/kwarc/mmt/latex/MMTTeX.scala +++ b/src/latex-mmt/src/info/kwarc/mmt/latex/MMTTeX.scala @@ -37,7 +37,7 @@ import MMTTeX._ */ class MMTTeX extends ShellExtension("mmttex") { def helpText: String = "" - + def run(shell: Shell, args: List[String]) = { val tex = File(args(0)) val base = DPath(FileURI(tex)) @@ -59,11 +59,11 @@ class MMTTeX extends ShellExtension("mmttex") { private val jobFile = new FileWriter(sty) private var modFiles: List[String] = Nil private val pres = new MacroBasedPresenter - + def doDocument(doc: Document) { doc.getModulesResolved(controller.globalLookup) foreach doModule } - + private def doModule(m: Module) { controller.simplifier(m) val modFileName = m.name.toPath @@ -117,7 +117,7 @@ object MacroUsingObjectPresenter extends ObjectPresenter { val nL = n.toPath val tpL = tp match { case None => "{}" - case Some(t) => "{" + doObj(t) + "}" + case Some(t) => "{" + doObj(t) + "}" } val dfL = df match { case None => @@ -137,7 +137,7 @@ object MacroUsingObjectPresenter extends ObjectPresenter { /** produces content of sty file for every theory */ class MacroBasedPresenter extends Presenter(MacroUsingObjectPresenter) { def key = "mmt-latex" - + def apply(e : StructuralElement, standalone: Boolean = false)(implicit rh : RenderingHandler) { e match { case t: DeclaredTheory => doTheory(t) @@ -152,7 +152,7 @@ class MacroBasedPresenter extends Presenter(MacroUsingObjectPresenter) { case d => doDeclaration(d) } } - + private def doDeclaration(d: Declaration)(implicit rh : RenderingHandler) {} /* d match { @@ -167,10 +167,10 @@ class MacroBasedPresenter extends Presenter(MacroUsingObjectPresenter) { doMarkers(tn.presentationMarkers) } rh << s"\\newcommand{${doConstantName(c.path)}}$numArgs{$notBody}" - case _ => // generate RequirePackage for every include + case _ => // generate RequirePackage for every include } } - + private def requirePackage(p: MPath, bf: BuildTask): String = { controller.backend.findOwningArchive(p) match { case None => "% skipping import of unknown module " + p.toPath diff --git a/src/latex-mmt/src/info/kwarc/mmt/latex/STeXMMTMerge.scala b/src/latex-mmt/src/info/kwarc/mmt/latex/STeXMMTMerge.scala index 7b5775cc1f..ad9b2db3e3 100644 --- a/src/latex-mmt/src/info/kwarc/mmt/latex/STeXMMTMerge.scala +++ b/src/latex-mmt/src/info/kwarc/mmt/latex/STeXMMTMerge.scala @@ -26,18 +26,18 @@ import STeXMMTMerge._ * the mmt content of the tex file is extracted into tex.mmt while running latex (or latexml), and the tex file is converted to omdoc via StexImporter * the tex content of tex.mmt file is extracted into tex.mmt.tex by running LatexPresenter, and the tex.mmt file is converted to omdoc by MMT * This is repeated until all nestings are processed, and the resulting omdoc files are merged. - * + * * This was written by Mihnea on relatively short notice. It is unclear if it ever worked well. */ class STeXMMTMerge extends ShellExtension("stexmmt") { def helpText: String = "" - + override def start(args : List[String]) { super.start(args) val li = new LatexInterpreter controller.extman.addExtension(li, Nil) } - + def run(shell: Shell, args: List[String]) = args match { // generate a sty file for an mmt file case "sty" :: fileName :: Nil => genSty(fileName) @@ -46,25 +46,25 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { // merge the omdoc files produced from an mmt and (via stex importer) tex file case "merge" :: fileName :: Nil => mergeFiles(File(fileName).getAbsoluteFile) // chain the above - case "make" :: fileName :: Nil => + case "make" :: fileName :: Nil => val file = File(fileName).getAbsoluteFile genFiles(file) mergeFiles(file) case _ => throw LocalError("Invalid Arguments: " + args.mkString) } - + def genFiles(srcFile : File) : Boolean = { val base : DPath = DPath(FileURI(srcFile)) _genFiles(srcFile, base) true } - + def _genFiles(srcFile : File, base : DPath) { val ext = srcFile.getExtension.getOrElse("tex") //default val altExt = if (ext == "tex") "mmt" else "tex" if (ext == "mmt") { genMMTFiles(srcFile, base) - } else {//.tex case + } else {//.tex case //should call shell script for now do nothing } val altFile = srcFile.addExtension(altExt) @@ -72,7 +72,7 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { _genFiles(altFile, base) } } - + def genMMTFiles(srcFile : File, base : DPath) { val ps = ParsingStream.fromFile(srcFile, formatOpt = Some("mmt"), dpathOpt = Some(base)) val ec = new ErrorContainer(None) @@ -80,7 +80,7 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { //write tex val lp = new LatexPresenter(new LatexObjectPresenter) initOther(lp) - val outFile = srcFile.addExtension("tex") + val outFile = srcFile.addExtension("tex") val rh = new presentation.StringBuilder lp.apply(doc, standalone = true)(rh) if (lp.counter > 1) File.write(srcFile.addExtension("tex"), rh.get) @@ -88,7 +88,7 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { val out = doc.toNodeResolved(controller.library, true).toString File.write(srcFile.addExtension("omdoc"), out) } - + def mergeFiles(srcFile : File) : Boolean = { val base : DPath = DPath(FileURI(srcFile)) val cont = new Controller() @@ -97,7 +97,7 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { File.write(srcFile.setExtension("omdoc"), newdoc.toString) true } - + var counter = 1 def _mergeFiles(srcFile : File, base : DPath, cont : Controller, cont_extra : Controller) { @@ -113,7 +113,7 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { importer.compileOne(src, base) cont.getDocument(base) } - + val altExt = if (srcExt == "tex") "mmt" else "tex" val altFile = srcFile.addExtension(altExt) if (altFile.exists) { @@ -122,9 +122,9 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { traverse(mainDoc, base, cont, cont_extra) } //else nothing to do } - + def traverse(s : StructuralElement, from : DPath, cont : Controller, cont_other : Controller) : Unit = s match { - case d : Document => + case d : Document => d.getDeclarations foreach { traverse(_, from, cont, cont_other) } @@ -132,7 +132,7 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { case t : DeclaredTheory => var refNames : List[LocalName] = Nil t.asDocument.getDeclarations foreach { - case oe: UnknownOpaqueElement if (oe.format == "latex" || oe.format == "mmt") => + case oe: UnknownOpaqueElement if (oe.format == "latex" || oe.format == "mmt") => val refId = "mixref" + counter counter += 1 val decls = cont_other.library.get(from / t.name / refId).getDeclarations flatMap { @@ -140,7 +140,7 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { case _ => Nil } decls.reverse foreach { - case c : Constant => + case c : Constant => c.setDocumentHome(c.relativeDocumentHome.init) t.addAfterNarrative(c, oe.name) case _ => //ignore for now @@ -151,30 +151,30 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { val tdoc = t.asDocument refNames foreach (tdoc.delete(_)) t.getDeclarations foreach { - case c : Constant => + case c : Constant => val thy : DeclaredTheory = cont_other.get(t.path).asInstanceOf[DeclaredTheory] c.tp.map(t => c.tpC.update(TermContainer(tr(t, cont_other.library -> thy)))) c.df.map(t => c.dfC.update(TermContainer(tr(t, cont_other.library -> thy)))) case _ => //ignore } - + case _ => //nothing to do } - + object tr extends Traverser[(Library, DeclaredTheory)] { def traverse(t: Term)(implicit con : Context, p : (Library, DeclaredTheory)) : Term = t match { - case OMV(name) if name.toPath.startsWith("mixref") => + case OMV(name) if name.toPath.startsWith("mixref") => val tm = p._2.get(name) match { case c : Constant => c.df.get } tm case OMV(name) => name.toString.split("@",-1).toList match { - case tname :: sname :: sterm :: Nil => + case tname :: sname :: sterm :: Nil => try { - val decl = if (tname == "") p._2.get(LocalName(sname)) + val decl = if (tname == "") p._2.get(LocalName(sname)) else p._1.get(p._2.parent ? tname ? sname) decl match { - case c : Constant => + case c : Constant => if (sterm == "") { OMS(c.path) } else { @@ -185,27 +185,27 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { } } } catch { - case e : Throwable => - val path = if (tname == "") p._2.path ? sname + case e : Throwable => + val path = if (tname == "") p._2.path ? sname else p._2.parent ? tname ? sname OMS(path) } - case l => + case l => Traverser(this, t) } case t => Traverser(this,t) } } - - - + + + /* - case c : Constant if (c.name.toPath.startsWith("mixref")) => + case c : Constant if (c.name.toPath.startsWith("mixref")) => val refId = c.name.toPath //.substring("mixref".length).toLowerCase() val decls = cont_other.library.get(from / t.name / refId).getDeclarations flatMap { case s : SRef => List(cont_other.get(s.target)) case _ => Nil - } + } decls.reverse foreach { case fc : Constant => val newC = new FinalConstant(OMMOD(t.path), fc.name, fc.alias, fc.tpC, fc.dfC, fc.rl, fc.notC) @@ -217,7 +217,7 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { cont.library.update(t) } */ - + def genSty(fname : String) : Boolean = { var response = "" val f = File(fname) @@ -230,7 +230,7 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { controller.extman.addExtension(op) // make sure it's initialized op } - def doModule(m: ContentElement) { + def doModule(m: ContentElement) { m.getDeclarations.foreach { case c: Constant => val name = c.name.toPath @@ -249,4 +249,4 @@ class STeXMMTMerge extends ShellExtension("stexmmt") { File.write(f.addExtension("sty"), response) true } -} \ No newline at end of file +} diff --git a/src/latex-mmt/src/info/kwarc/mmt/latex/UnicodeConverter.scala b/src/latex-mmt/src/info/kwarc/mmt/latex/UnicodeConverter.scala index b87ed4013f..928f2a2fd3 100644 --- a/src/latex-mmt/src/info/kwarc/mmt/latex/UnicodeConverter.scala +++ b/src/latex-mmt/src/info/kwarc/mmt/latex/UnicodeConverter.scala @@ -208,4 +208,4 @@ jomega|ω } } init -} \ No newline at end of file +} diff --git a/src/latex-mmt/src/info/kwarc/mmt/latex/stex.scala b/src/latex-mmt/src/info/kwarc/mmt/latex/stex.scala index fcca1c1bff..6b34a39c6c 100644 --- a/src/latex-mmt/src/info/kwarc/mmt/latex/stex.scala +++ b/src/latex-mmt/src/info/kwarc/mmt/latex/stex.scala @@ -17,4 +17,4 @@ case class ImportModule(thy: MPath) extends StexDeclaration { case class SymDef(parent: MPath, name: LocalName) extends StexDeclaration { override def toString = s"""\\symdef{${name.toPath}}{${name.toPath}}""" -} \ No newline at end of file +} diff --git a/src/lfcatalog/src/info/kwarc/mmt/twelf/catalog.scala b/src/lfcatalog/src/info/kwarc/mmt/twelf/catalog.scala index 0f8eef9154..4e9f381b59 100644 --- a/src/lfcatalog/src/info/kwarc/mmt/twelf/catalog.scala +++ b/src/lfcatalog/src/info/kwarc/mmt/twelf/catalog.scala @@ -33,57 +33,57 @@ object Catalog { * @param crawlingInterval interval, in seconds, between two automatic crawls. Default value is 30 sec * @param deletingInterval interval, in seconds, between two automatic deletions (from hashes) of files that no longer exist on disk. Default value is 17 sec */ -class Catalog(val locationsParam: HashSet[String] = HashSet(), - val inclusionsParam: HashSet[String] = HashSet("*.elf"), - val exclusionsParam: HashSet[String] = HashSet(".svn"), - var port: Int = 8080, +class Catalog(val locationsParam: HashSet[String] = HashSet(), + val inclusionsParam: HashSet[String] = HashSet("*.elf"), + val exclusionsParam: HashSet[String] = HashSet(".svn"), + var port: Int = 8080, val searchPort: Boolean = false, val log: String => Unit = println, - val crawlingInterval: Int = 30, + val crawlingInterval: Int = 30, val deletingInterval: Int = 17) { import Catalog._ - + // ------------------------------- public members ------------------------------- - + /** Locations (files and folders) being watched */ val locations = HashSet[File] () - + /** Map from URLs to documents. Its key set is the set of file URLs that are currently indexed */ val urlToDocument = HashMap[URI, Document] () - + /** Map from URIs to named blocks (modules, declarations or assignments) */ val uriToNamedBlock = HashMap[URI, NamedBlock] () - + /** Map from namespace URIs to modules declared in that URI */ val uriToModulesDeclared = HashMap[URI, LinkedHashSet[URI]] () - - + + // ------------------------------- private members ------------------------------- - - + + /** Exclusion patterns for files and folders. */ private val exclusions = HashSet[String] () - + /** Inclusion patterns for files */ private val inclusions = HashSet[String] () - + /** Processed exclusion and inclusion patterns (for internal use) * Everything is quoted, except *, which are replaced with .* */ private val processedExclusions = HashSet[String] () private val processedInclusions = HashSet[String] () - + /** the RESTful web server */ private var server : WebServer = null - + /** background processes */ private val bkgCrawler = new BackgroundCrawler(this, crawlingInterval) private val bkgEliminator = new BackgroundEliminator(this, deletingInterval) - - + + // ------------------------------- initialization and destruction ------------------------------- - - + + /** Start the web server, background threads, add given patterns & locations * @return the port number, which can be different from the port specified in the constructor * @throws PortUnavailable if the web server cannot be started because the specified port is already in use */ @@ -100,18 +100,18 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), throw PortUnavailable(port.toString) else port = newPort } - + // construct server (it reads the resource pages when constructed) server = new WebServer(this, port) - + // start background threads that make sure this catalog is synchronized with the disk bkgCrawler.start bkgEliminator.start - + // add inclusion and exclusion patterns inclusionsParam.foreach(addInclusion) exclusionsParam.foreach(addExclusion) - + // add locations for (l <- locationsParam) try { @@ -119,14 +119,14 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), } catch { case InexistentLocation(msg) => log(msg) } - + // start the web server (different threads) server.start log("go to: http://127.0.0.1:" + port) return port } - - + + /** Stop the web server */ def destroy { server.stop @@ -137,33 +137,33 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), uriToNamedBlock.clear uriToModulesDeclared.clear } - - + + // ------------------------------- getter methods ------------------------------- - - + + /** The URI for querying the catalog with getText */ def queryURI : String = "http://localhost:" + port + "/getPositionInHeader" - - - /** Exclusion patterns for files and folders. - * Star is the only special character and matches any sequence of characters. + + + /** Exclusion patterns for files and folders. + * Star is the only special character and matches any sequence of characters. * A folder is crawled iff it doesn't match any exclusion pattern. * A file is crawled iff it matches at least one inclusion pattern, but no exclusion pattern. However, if no inclusion patterns are provided, only the second condition remains. */ def getExclusions : HashSet[String] = exclusions - + /** Inclusion patterns for files - * Star is the only special character and matches any sequence of characters. + * Star is the only special character and matches any sequence of characters. * A folder is crawled iff it doesn't match any exclusion pattern. * A file is crawled iff it matches at least one inclusion pattern, but no exclusion pattern. However, if no inclusion patterns are provided, only the second condition remains. */ def getInclusions : HashSet[String] = inclusions - + /** Get the semantic comment associated with a document, module, constant or structure * @param stringUri URI of a module or URL of a document, given as string * @param asText set it to true for text output and to false for XML output * @return if asText is true, the semantic comment, copied character by character from the file. Otherwise, an XML representation of the comment - * @throws java.net.URISyntaxException if stringUri does not point to a location on disk and, as a URI, it is not valid + * @throws java.net.URISyntaxException if stringUri does not point to a location on disk and, as a URI, it is not valid * @throws CatalogError(s: String) if the URI/URL is unknown */ def getMeta(stringUri : String, asText : Boolean = false) : String = { val document = new File(stringUri) @@ -182,7 +182,7 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), throw CatalogError("") } catch { // If it doesn't point to a file on the disk, maybe it's a module URI case _ : Throwable => { - uri = new URI(stringUri) + uri = new URI(stringUri) if (uriToNamedBlock.isDefinedAt(uri)) if (asText == true) uriToNamedBlock(uri).associatedComment.map(_.comment).getOrElse("") @@ -193,13 +193,13 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), } } } - - + + /** Get the text of an entity. The HTTP header also has a field X-Source-url, followed by the position of the entity as returned by getPosition * Warning: this function reads the disk, since the text is not stored in memory. * @param stringUri URI of a module or URL of a document, given as string * @return the actual content, read from the file - * @throws java.net.URISyntaxException if stringUri does not point to a location on disk which is also stored in memory and, as a URI, it is not valid + * @throws java.net.URISyntaxException if stringUri does not point to a location on disk which is also stored in memory and, as a URI, it is not valid * @throws CatalogError(s: String) if the URI/URL is unknown * @throws FileOpenError(s) if the file cannot be read */ def getText(stringUri : String) : String = { @@ -220,13 +220,13 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), return lines.mkString("\n") } catch { case e : Throwable => throw FileOpenError("error: file cannot be opened or the encoding is not UTF-8") - } + } } else throw CatalogError("") } catch { // If it doesn't point to a file on the disk, maybe it's a module URI case _ : Throwable => { - uri = new URI(stringUri) + uri = new URI(stringUri) if (uriToNamedBlock.isDefinedAt(uri)) { val namedBlock = uriToNamedBlock(uri) // presumably a theory or a view val url = namedBlock.url @@ -251,13 +251,13 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), } } } - - - + + + /** Get all dependencies of a module, constant or structure * @param stringUri URI of a module / constant / structure, given as a string * @return an array of dependency URIs, given as strings - * @throws java.net.URISyntaxException if the URI is not valid + * @throws java.net.URISyntaxException if the URI is not valid * @throws CatalogError(s: String) if the URI is unknown */ def getDependencies(stringUri : String) : Array[String] = { val uri = new URI(stringUri) @@ -271,12 +271,12 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), else throw CatalogError("") } - - + + /** Get all children of a namespace URI, module, constant or structure * @param stringUri URI of a module / constant / structure, given as a string * @return an array of children URIs, given as strings - * @throws java.net.URISyntaxException if the URI is not valid + * @throws java.net.URISyntaxException if the URI is not valid * @throws CatalogError(s: String) if the URI is unknown */ def getChildren(stringUri : String) : Array[String] = { val uri = new URI(stringUri) @@ -290,12 +290,12 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), else throw CatalogError("") } - - + + /** Get the position of a module, constant or structure. * @param stringUri URI of a module / constant / structure, given as a string * @return an URL encoding the file and the position within that file - * @throws java.net.URISyntaxException if the URI is not valid + * @throws java.net.URISyntaxException if the URI is not valid * @throws CatalogError(s: String) if the URI is unknown */ def getPosition(stringUri : String) : String = { val uri = new URI(stringUri) @@ -304,9 +304,9 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), else throw CatalogError("") } - - - + + + /** Get a document skeleton as Omdoc * @param stringUrl URL (location on disk) of a document, given as a string * @return the document as Omdoc @@ -326,8 +326,8 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), else throw CatalogError("Unknown URL: " + stringUrl) } - - + + /** Get all namespaces URIs introduced by a document * @param stringUrl URL (location on disk) of a document, given as a string * @return an array of namespace URIs given as strings @@ -347,20 +347,20 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), else throw CatalogError("Unknown URL: " + stringUrl) } - - + + /** Get the list of namespaces declared in all the files in all the maintained locations * @return an array of namespace URIs given as strings */ def getNamespaces() : Array[String] = urlToDocument.values.map(_.declaredNamespaces.map(_.toString)) .foldLeft (SortedSet[String]()) ((set, iterable) => set ++ iterable) .toArray - - + + /** Get the modules introduced by a namespace, in alphabetical order * @param stringUri a namespace URI, given as a string * @return an URL encoding the file and the position within that file - * @throws java.net.URISyntaxException if the URI is not valid + * @throws java.net.URISyntaxException if the URI is not valid * @throws CatalogError(s: String) if the namespace URI is unknown */ def getModulesInNamespace(stringUri : String) : Array[String] = { val uri = new URI(stringUri) @@ -369,8 +369,8 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), else throw CatalogError("") } - - + + /** Write the Omdoc skeleton to a file with the same name as the original and in the same folder, but with extension .omdocsk * @param stringUrl the URL of the .elf file to be converted. * @throws CatalogError(s) if the URL is not OK or not crawled already */ @@ -385,21 +385,21 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), } catch { case _ : Throwable => throw CatalogError("Invalid URL: " + realUrl) } - + var toWrite : String = "" if (urlToDocument.isDefinedAt(url)) toWrite = "" + new PrettyPrinter(80,2).format(urlToDocument(url).toOmdoc) else throw CatalogError("Unknown URL: " + realUrl) - - var newName : String = "" + + var newName : String = "" if (document.getName.lastIndexOf(".") == -1) newName = document.getName + ".omdocsk" else newName = document.getName.substring(0, document.getName.lastIndexOf(".")) + ".omdocsk" val outFile = url.resolve(newName).toString var out : BufferedWriter = null - + try { out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),"UTF8")); } catch { @@ -408,11 +408,11 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), out.write(toWrite) out.close } - - + + // ------------------------------- setter methods ------------------------------- - - + + /** Add an inclusion pattern to the storage */ def addInclusion(pattern : String) { if (pattern == "") @@ -423,8 +423,8 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), processedInclusions += quotePattern(pattern) } } - - + + /** Add an exclusion pattern to the storage */ def addExclusion(pattern : String) { if (pattern == "") @@ -435,8 +435,8 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), processedExclusions += quotePattern(pattern) } } - - + + /** Add a location by its string address. * If the location is a descendant of an already watched folder, it is not added. * If the location is an ancestor of an already watched location, then it is added and the already watched location is removed. @@ -446,9 +446,9 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), val location = new File(locationName) if (location == null || !location.canRead) throw InexistentLocation(getOriginalPath(location) + ": error: location does not exist or cannot be read") - + val path : String = getPath(location) - + if (!isLegalLocation(location.getName, location.isDirectory)) log(Time + getOriginalPath(location) + ": warning: location is ignored because it does not match the given patterns") else { @@ -470,8 +470,8 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), } } } - - + + /** Delete from watch list a location given by its string address. * @param locationName the (absolute or relative) address of the location on disk * @throws InexistentLocation if the location is not in the watch list */ @@ -479,7 +479,7 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), val location = new File(locationName) if (location == null || !location.canRead) throw InexistentLocation(getOriginalPath(location) + ": error: location does not exist or cannot be read, hence it cannot be deleted") - + if (locations contains location) { locations -= location uncrawl(getPath(location)) @@ -487,26 +487,26 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), } else throw InexistentLocation(getOriginalPath(location) + ": error: location is not in the watch list, hence it cannot be deleted") } - - + + // ------------------------------- crawling ------------------------------- - - + + /** Crawl through all stored locations, ignoring (but logging) errors */ def crawlAll { locations.foreach(crawl) } - - + + /** Clear the storage */ def uncrawlAll { locations.map(getPath).foreach(uncrawl) } - + /** Delete all the hash entries associated with a specific file or folder * @param location the file or folder URL, as a string */ - def uncrawl(url: String) { ConflictGuard.synchronized { + def uncrawl(url: String) { ConflictGuard.synchronized { val crawledFiles = urlToDocument.filterKeys(_.toString.startsWith(url)) // the file itself, or all files in the given folder for ((url, doc) <- crawledFiles) { doc.modules.foreach(m => { @@ -528,27 +528,27 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), urlToDocument -= url } }} - - + + /** Crawl through a specific file or folder * @param location the file or folder descriptor */ - def crawl(location: File) { ConflictGuard.synchronized { + def crawl(location: File) { ConflictGuard.synchronized { if (!location.canRead) { log(Time + getOriginalPath(location) + ": error: file/folder does not exist or cannot be read") return } val locationName = location.getName // name without the path - + if (location.isDirectory()) { // It's a folder. Crawl it iff it doesn't match any exclusion pattern. if (isLegalLocation(locationName, true)) { - + // Get list of children var fileList : Array[File] = null try { fileList = location.listFiles() } catch { - case e : SecurityException => { + case e : SecurityException => { log(Time + getOriginalPath(location) + ": error: folder cannot be read") return } @@ -557,7 +557,7 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), log(Time + getOriginalPath(location) + ": error: folder cannot be read") return } - + // Crawl through the children fileList.foreach(crawl) } @@ -574,7 +574,7 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), uncrawl(path.toString) } } - + // Crawl the file iff it matches at least one inclusion pattern, but no exclusion pattern. However, if no inclusion patterns are provided, then all files are crawled. if (isLegalLocation(locationName, false)) { try { @@ -594,11 +594,11 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), } } document.lastModified = lastModified - + // Throw CatalogError if the file has been read before or any component URI is defined elsewhere if (urlToDocument.isDefinedAt(document.url)) throw CatalogError("error: the url of this document (" + document.url + ") has already been encountered elsewhere") - + for (m <- document.modules) { if (uriToNamedBlock.isDefinedAt(m.uri)) throw CatalogError(m.pos + ": error: the uri of this module (" + m.uri + ") has already been encountered at " + getPosition(m.uri.toString)) @@ -609,7 +609,7 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), throw CatalogError(c.pos + ": error: the uri of this assignment (" + c.uri + ") has already been encountered at " + getPosition(c.uri.toString)) } } - + // Update hashes urlToDocument.update(document.url, document) document.modules.foreach(m => { @@ -626,7 +626,7 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), }) case ViewBlock(_,_,_,children,_,_,_,_) => children.foreach(c => uriToNamedBlock.update(c.uri, c)) }}) - + // Print the parsing errors; if there are none, print "OK" if (document.errors.isEmpty) log(Time + getOriginalPath(location) + ": OK") @@ -640,23 +640,23 @@ class Catalog(val locationsParam: HashSet[String] = HashSet(), } } }} - - + + // ------------------------------- private methods ------------------------------- - - + + /** Check whether a location matches the stored patterns. * @param locationName the file or folder name, excluding its path * @param isDirectory set it to true if the location is a directory name, otherwise set it to false * @return For directories: true if and only if it doesn't match any exclusion pattern. For files: true if and only if it matches at least one inclusion pattern, but no exclusion pattern. However, if no inclusion patterns are provided, only the second condition remains. */ - private def isLegalLocation(locationName: String, isDirectory: Boolean) : Boolean = + private def isLegalLocation(locationName: String, isDirectory: Boolean) : Boolean = if (isDirectory) !processedExclusions.exists(locationName.matches) - else + else (processedInclusions.isEmpty || processedInclusions.exists(locationName.matches)) && !processedExclusions.exists(locationName.matches) - - + + /** Translates a given pattern into a Java regexp. * @param pattern the pattern to be processed, given as a string. The only special character is *, which is interpreted as any sequence of characters. * @return a Java regexp pattern with the same meaning as the one given as parameter */ @@ -701,4 +701,4 @@ class BackgroundEliminator(val catalog: Catalog, val deletingInterval: Int) exte } } } -} \ No newline at end of file +} diff --git a/src/lfcatalog/src/info/kwarc/mmt/twelf/document.scala b/src/lfcatalog/src/info/kwarc/mmt/twelf/document.scala index 290d0eb72f..1073adba24 100644 --- a/src/lfcatalog/src/info/kwarc/mmt/twelf/document.scala +++ b/src/lfcatalog/src/info/kwarc/mmt/twelf/document.scala @@ -14,13 +14,13 @@ import scala.collection.mutable.{HashSet, LinkedHashSet, MutableList, LinkedHash * @param prefixes mapping from namespace prefixes to their URI * @param declaredNamespaces list of current namespaces declared in the document * @param The errors that occurred during parsing */ -class Document(val url: URI, val associatedComment: Option[SemanticCommentBlock], val modules: MutableList[ModuleBlock], +class Document(val url: URI, val associatedComment: Option[SemanticCommentBlock], val modules: MutableList[ModuleBlock], val prefixes: LinkedHashMap[String,URI], val declaredNamespaces: LinkedHashSet[URI], var errors: List[ParseError]) { - + /** Time, in miliseconds, when the file was last modified */ var lastModified : Long = -1 - - def toOmdoc : Elem = + + def toOmdoc : Elem = {associatedComment.map(_.toOmdoc).getOrElse(Seq.empty)} {modules.map(_.toOmdoc)} @@ -37,16 +37,16 @@ class Document(val url: URI, val associatedComment: Option[SemanticCommentBlock] * @param c end line * @param d end column */ class Position(a: Int, b: Int, c: Int, d: Int) { - + /** @param x start position (line and column) @param y end position (line and column) */ def this(x: (Int,Int), y: (Int,Int)) = this(x._1, x._2, y._1, y._2) - + /** begin */ def _1 = (a,b) /** end */ def _2 = (c,d) - + /** Format: startline.startcol-endline.endcol */ override def toString = a + "." + b + "-" + c + "." + d } @@ -60,8 +60,8 @@ abstract class Block(pos: Position) { /** A semantic comment - * The "short" property is the text on the first line of the comment, if it is not preceded by a '@' - * The "long" property is the text starting on the second line of the comment, until the first line that starts with '@' + * The "short" property is the text on the first line of the comment, if it is not preceded by a '@' + * The "long" property is the text starting on the second line of the comment, until the first line that starts with '@' * Each subsequent lines must start with '@'. The first word after '@' is the key, the rest of the line is the value. */ case class SemanticCommentBlock(val comment: String, val properties: LinkedHashMap[String, String], val pos: Position) extends Block(pos) { def toOmdoc : Elem = @@ -82,14 +82,14 @@ abstract class NamedBlock(val uri: URI, val url: URI, val name: String, val pos: /** A theory or view */ -abstract class ModuleBlock(override val uri: URI, override val url: URI, override val name: String, val deps: LinkedHashSet[URI], override val pos: Position) +abstract class ModuleBlock(override val uri: URI, override val url: URI, override val name: String, val deps: LinkedHashSet[URI], override val pos: Position) extends NamedBlock(uri, url, name, pos) - + /** A theory */ -case class SigBlock(override val uri: URI, override val url: URI, override val name: String, val children: MutableList[DeclBlock], override val deps: LinkedHashSet[URI], override val pos: Position) +case class SigBlock(override val uri: URI, override val url: URI, override val name: String, val children: MutableList[DeclBlock], override val deps: LinkedHashSet[URI], override val pos: Position) extends ModuleBlock(uri, url, name, deps, pos) { - override def toOmdoc : Elem = + override def toOmdoc : Elem = {associatedComment.map(_.toOmdoc).getOrElse(Seq.empty)} {children.map(_.toOmdoc)} @@ -100,62 +100,62 @@ case class SigBlock(override val uri: URI, override val url: URI, override val n /** A view */ case class ViewBlock(override val uri: URI, override val url: URI, override val name: String, val children: MutableList[AssignmentBlock], override val deps: LinkedHashSet[URI], val domain: URI, val codomain: LinkedHashSet[URI], override val pos: Position) extends ModuleBlock(uri, url, name, deps, pos) { - override def toOmdoc : Elem = + override def toOmdoc : Elem = {associatedComment.map(_.toOmdoc).getOrElse(Seq.empty)} {children.map(_.toOmdoc)} } - + // ------------------------------- symbol-level ------------------------------- - + /** A constant or structure assignment */ -abstract class AssignmentBlock(override val uri: URI, override val url: URI, override val name: String, override val pos: Position) +abstract class AssignmentBlock(override val uri: URI, override val url: URI, override val name: String, override val pos: Position) extends NamedBlock(uri, url, name, pos) - + /** A constant assignment */ -case class CstAssignmentBlock(override val uri: URI, override val url: URI, override val name: String, override val pos: Position) +case class CstAssignmentBlock(override val uri: URI, override val url: URI, override val name: String, override val pos: Position) extends AssignmentBlock(uri, url, name, pos) { - override def toOmdoc : Elem = + override def toOmdoc : Elem = {associatedComment.map(_.toOmdoc).getOrElse(Seq.empty)} } - + /** A structure assignment */ -case class StrAssignmentBlock(override val uri: URI, override val url: URI, override val name: String, override val pos: Position) +case class StrAssignmentBlock(override val uri: URI, override val url: URI, override val name: String, override val pos: Position) extends AssignmentBlock(uri, url, name, pos) { - override def toOmdoc : Elem = + override def toOmdoc : Elem = {associatedComment.map(_.toOmdoc).getOrElse(Seq.empty)} } - - - + + + /** A constant or structure declaration */ -abstract class DeclBlock(override val uri: URI, override val url: URI, override val name: String, override val pos: Position) +abstract class DeclBlock(override val uri: URI, override val url: URI, override val name: String, override val pos: Position) extends NamedBlock(uri, url, name, pos) - + /** A constant declaration */ -case class CstDeclBlock(override val uri: URI, override val url: URI, override val name: String, override val pos: Position) +case class CstDeclBlock(override val uri: URI, override val url: URI, override val name: String, override val pos: Position) extends DeclBlock(uri, url, name, pos) { override def toOmdoc : Elem = {associatedComment.map(_.toOmdoc).getOrElse(Seq.empty)} } - + /** A structure declaration */ -case class StrDeclBlock(override val uri: URI, override val url: URI, override val name: String, val children: MutableList[AssignmentBlock], val domain: Option[URI], override val pos: Position) +case class StrDeclBlock(override val uri: URI, override val url: URI, override val name: String, val children: MutableList[AssignmentBlock], val domain: Option[URI], override val pos: Position) extends DeclBlock(uri, url, name, pos) { - override def toOmdoc : Elem = + override def toOmdoc : Elem = {associatedComment.map(_.toOmdoc).getOrElse(Seq.empty)} {children.map(_.toOmdoc)} -} \ No newline at end of file +} diff --git a/src/lfcatalog/src/info/kwarc/mmt/twelf/fileCrawler.scala b/src/lfcatalog/src/info/kwarc/mmt/twelf/fileCrawler.scala index 2a0f138f0f..3333886090 100644 --- a/src/lfcatalog/src/info/kwarc/mmt/twelf/fileCrawler.scala +++ b/src/lfcatalog/src/info/kwarc/mmt/twelf/fileCrawler.scala @@ -20,21 +20,21 @@ object FileCrawler { /** Algorithms for crawling a file * @param file the file descriptor */ class FileCrawler(file : File) { - + // ------------------------------- private members ------------------------------- - + /** array containing all the lines in the file */ private var lines : Array[String] = null - + /** all the lines in a single string, with " " instead of newline. */ private var flat : String = "" - + /** array of pairs . All indexes are 0-based. */ private implicit var lineStarts = new ArraySeq [(Int, Int)] (0) - + /** list of parsing errors in the file */ private var errors : List[ParseError] = Nil - + /** temporary variable used during parsing: saves the last SemanticCommentBlock */ private var keepComment : Option[SemanticCommentBlock] = None @@ -44,7 +44,7 @@ class FileCrawler(file : File) { try { val source = scala.io.Source.fromFile(file, "utf-8") lines = source.getLines.toArray // get all lines from the file - source.asInstanceOf[scala.io.BufferedSource].close // close the file, since scala.io.Source doesn't close it + source.asInstanceOf[scala.io.BufferedSource].close // close the file, since scala.io.Source doesn't close it } catch { case e : Throwable => throw FileOpenError("error: file cannot be opened or the encoding is not UTF-8") } @@ -54,11 +54,11 @@ class FileCrawler(file : File) { flat += x + "\n" lineNumber += 1 } - - + + // ------------------------------- main method ------------------------------- - - + + /** Crawl a file. * @return a Document object containing the extracted information, which includes a LinkedList of errors occurred during parsing * @throws ParseError for syntactical errors in the file */ @@ -66,29 +66,29 @@ class FileCrawler(file : File) { { // temporary variable used during parsing: the namespace URI which is in effect at the current place in the file var currentNS : Option[URI] = None - + // the optional semantic comment associated with the document var associatedComment : Option[SemanticCommentBlock] = None - + // theories and views var modules = new MutableList[ModuleBlock] () - + // mapping from namespace prefixes to their URI var prefixes = new LinkedHashMap[String,URI] () - + // list of current namespaces declared in the document - var declaredNamespaces = new LinkedHashSet[URI] () - + var declaredNamespaces = new LinkedHashSet[URI] () + var i = 0 // position in the flattened file - - // Read the optional semantic comment about the document + + // Read the optional semantic comment about the document i = skipws(i) if (i < flat.length && flat.startsWith("%*", i)) { val (comment, positionAfter) = crawlSemanticCommentBlock(i) associatedComment = Some(comment) i = positionAfter } - + keepComment = None // reset the last semantic comment stored i = skipwscomments(i) // check whether there is a new semantic comment @@ -137,17 +137,17 @@ class FileCrawler(file : File) { } else throw ParseError(toPair(i, lineStarts) + ": error: unknown entity. Module, comment or namespace declaration expected") - + keepComment = None // reset the last semantic comment stored i = skipwscomments(i) // check whether there is a new semantic comment } return new Document(new URI(Catalog.getPath(file)), associatedComment, modules, prefixes, declaredNamespaces, errors) } - - + + // ------------------------------- crawl-forward ------------------------------- - - + + /** Jump over a line. * @param start a position within a line * @return the index of the beginning of the next line */ @@ -158,24 +158,24 @@ class FileCrawler(file : File) { case e : NoSuchElementException => flat.length // there is no next line } } - + /** Jump over white space - * @param start the starting position, assumed to be white space + * @param start the starting position, assumed to be white space * @return the index of the first non-whitespace character. If the character at the starting position is not a white space, then it returns start */ - private def skipws(start: Int) : Int = + private def skipws(start: Int) : Int = { var i = start while (i < flat.length && Character.isWhitespace(flat.charAt(i))) i += 1 return i } - - /** Jump over all comments and white spaces. - * Side-effect: the last %* ... *% comment is saved in keepComment + + /** Jump over all comments and white spaces. + * Side-effect: the last %* ... *% comment is saved in keepComment * @param start the starting position * @return the first position >= start which is NOT white space or part of a comment * @throws ParseError for syntactical errors in the comments encountered */ - private def skipwscomments(start: Int) : Int = + private def skipwscomments(start: Int) : Int = { var i = skipws(start) var break = false @@ -198,8 +198,8 @@ class FileCrawler(file : File) { } return i } - - + + /** Jump over a block surrounded by curly brackets. * Skips over comments, strings and everything else. * @param start the position of an open { @@ -229,20 +229,20 @@ class FileCrawler(file : File) { throw ParseError(toPair(start, lineStarts) + ": error: left bracket { does not close") return -1 } - - + + /** Find the first white space. * @param start the position where to start looking * @return the position of the first white space */ - private def skipUntilWs(start: Int) : Int = + private def skipUntilWs(start: Int) : Int = { var i = start while (i < flat.length && !Character.isWhitespace(flat.codePointAt(i))) i += Character.charCount(flat.codePointAt(i)) return i } - - + + /** Find the first dot which is not part of an identifier. Useful for jumping over a declaration. * Skips over comments and quote-surrounded strings, so dots inside them do not count. * @param start the position where to start looking @@ -274,10 +274,10 @@ class FileCrawler(file : File) { throw ParseError("error: dot expected before end of file") } - + // ------------------------------- peek-forward ------------------------------- - - + + /** Find the position of the given string, after some white space and (possibly) some comments. * @param start the starting position * @param whatToExpect the string to find @@ -285,7 +285,7 @@ class FileCrawler(file : File) { * @param acceptComments if true, then all comments are ignored. If false, then only white space is allowed before whatToExpect. * @return the position of the first character in the whatToExpect string, if it is right after white space (and possibly comments). * @throws ParseError if the string after white space is not whatToExpect. */ - private def expectNext(start: Int, whatToExpect: String, error: String, acceptComments: Boolean = true) : Int = + private def expectNext(start: Int, whatToExpect: String, error: String, acceptComments: Boolean = true) : Int = { var i = 0 if (acceptComments) @@ -296,42 +296,42 @@ class FileCrawler(file : File) { throw ParseError(error) return i } - - + + // ------------------------------- object-level ------------------------------- - - + + /** Check whether a character, given as a unicode (UTF-8) code point is valid within an identifier part - * @param c a Unicode code point + * @param c a Unicode code point * @return true iff c not one of .:()[]{}%" or white space */ - private def isIdentifierPartCharacter(c: Int) : Boolean = + private def isIdentifierPartCharacter(c: Int) : Boolean = !Character.isWhitespace(c) && c != '.' && c != ':' && c != '(' && c != ')' && c != '[' && c != ']' && c != '{' && c != '}' && c != '%' && c != '"' - - + + /** Read a quote-surrounded string * @param start the position of the quotes at the beginning of the string * @return a pair of the string and the position after the final " * @throws ParseError if the string does not close */ - private def crawlString(start: Int) : (String, Int) = + private def crawlString(start: Int) : (String, Int) = { val endsAt = flat.indexOf('"', start + 1) // position of the final quotes if (endsAt == -1) throw ParseError(toPair(start, lineStarts) + ": error: the string does not close") return (flat.substring(start + 1, endsAt), endsAt + 1) } - - + + /** Read an identifier. * @param start the position of the first character of the identifier * @return Pair(identifier as a string, position after the last character of the identifier) * @throws ParseError if the current position does not start an identifier */ - private def crawlIdentifier(start: Int) : (String, Int) = + private def crawlIdentifier(start: Int) : (String, Int) = { var i = start // the current position var c = flat.codePointAt(i) // the current code point var previousCharacterCount = 1 // the size of the previous code point - + while (i < flat.length && (c == '.' || isIdentifierPartCharacter(c))) { previousCharacterCount = Character.charCount(c) i += previousCharacterCount @@ -339,25 +339,25 @@ class FileCrawler(file : File) { } if (flat.codePointAt(i - previousCharacterCount) == '.') // dot shouldn't be the last character in the identifier, so it belongs outside it i -= previousCharacterCount - + val myId = flat.substring(start, i) if (myId.isEmpty) throw ParseError(toPair(start, lineStarts) + ": error: identifier expected") return (myId, i) } - - + + // ------------------------------- namespace declarations ------------------------------- - - - /** Read a namespace block + + + /** Read a namespace block * @param start the position of the initial % * @return (Option[alias], URI, position). If this is a namespace alias declaration, then URI is the relative URI that alias points to. If this is an absolute namespace declaration, then the first return value is None and URI is the absolute URI that was read. In all cases, position is the position after the closing dot * @throws ParseError for syntactical errors */ - private def crawlNamespaceBlock(start: Int) : (Option[String], URI, Int) = + private def crawlNamespaceBlock(start: Int) : (Option[String], URI, Int) = { var i = skipws(start + "%namespace".length) // jump over %namespace - + // An absolute URI which becomes the current namespace URI if (flat.charAt(i) == '"') { val (string, positionAfterString) = crawlString(i) @@ -368,7 +368,7 @@ class FileCrawler(file : File) { case exc: java.net.URISyntaxException => throw ParseError(toPair(i, lineStarts) + ": error: " + exc.getMessage) } return (None, uri, 1 + expectNext(positionAfterString, ".", toPair(start, lineStarts) + ": error: %namespace statement does not end with a dot", false)) - + } // A namespace alias declaration else { @@ -376,7 +376,7 @@ class FileCrawler(file : File) { i = positionAfter i = 1 + expectNext(i, "=", toPair(start, lineStarts) + ": error: %namespace statement does not have '='", false) i = expectNext(i, "\"", toPair(start, lineStarts) + ": error: %namespace statement does not have a definiens", false) - + val (string, positionAfterString) = crawlString(i) // read the URI var uri : URI = null try { @@ -387,16 +387,16 @@ class FileCrawler(file : File) { return (Some(alias), uri, 1 + expectNext(positionAfterString, ".", toPair(start, lineStarts) + ": error: %namespace statement does not end with a dot", false)) } } - - + + // ------------------------------- comments ------------------------------- - - + + /** Jump over a non-semantic %{ comment }% * @param start the position of the initial % - * @return the position after the final % + * @return the position after the final % * @throws ParseError if the comment does not close */ - private def crawlCommentThrowBlock(start: Int) : Int = + private def crawlCommentThrowBlock(start: Int) : Int = { var i = start + "%{".length i = flat.indexOf("}%", i) //TODO handle nested comments @@ -404,30 +404,30 @@ class FileCrawler(file : File) { throw ParseError(toPair(start, lineStarts) + ": error: comment does not close") return i + "}%".length } - - + + /** Read a semantic %* comment *% * @param start the position of the initial % * @return The first return value is the structured comment, saved in a block, whose end position is on the final %. The second return value is the position after the block. * @throws ParseError if the comment does not close. Syntactical errors are only printed */ - private def crawlSemanticCommentBlock(start: Int) : (SemanticCommentBlock, Int) = + private def crawlSemanticCommentBlock(start: Int) : (SemanticCommentBlock, Int) = { var endsAt : Int = flat.indexOf("*%", start) // position of the final * if (endsAt == -1) throw ParseError(toPair(start, lineStarts) + ": error: comment does not close") endsAt += 1 // position of the final % val properties = LinkedHashMap[String, String] () - + val entireComment = flat.substring(start+2, endsAt-1).trim val commentLines = entireComment.split("\n") - var firstPropertyLine = commentLines.indexWhere(_.trim.startsWith("@")) - if (firstPropertyLine == -1) firstPropertyLine = commentLines.length - + var firstPropertyLine = commentLines.indexWhere(_.trim.startsWith("@")) + if (firstPropertyLine == -1) firstPropertyLine = commentLines.length + // Add the short comment if (firstPropertyLine >= 1 && commentLines(0).trim.nonEmpty) properties += (("short", commentLines(0).trim)) - + // Add the long comment if (firstPropertyLine >= 2) if (commentLines.slice(1, firstPropertyLine).mkString("\n").trim.nonEmpty) { @@ -437,7 +437,7 @@ class FileCrawler(file : File) { val lastNonEmptyLine = longCommentLines.lastIndexWhere(_.trim.nonEmpty) properties += (("long", longCommentLines.slice(firstNonEmptyLine, lastNonEmptyLine + 1).mkString("\n"))) } - + // Add the key-value properties var propertyLines : Array[String] = null try { @@ -458,11 +458,11 @@ class FileCrawler(file : File) { } catch { case e : ParseError => errors = (errors :+ e) // add to the list of errors returned } - return (new SemanticCommentBlock(entireComment, properties, - new Position(toPair(start, lineStarts), toPair(endsAt, lineStarts))), + return (new SemanticCommentBlock(entireComment, properties, + new Position(toPair(start, lineStarts), toPair(endsAt, lineStarts))), endsAt + 1) } - + // ------------------------------- symbol-level ------------------------------- @@ -472,7 +472,7 @@ class FileCrawler(file : File) { * @param parentURI the URI of the parent module * @return Pair(a CstDecl containing the information from the constant declaration, position after the block) * @throws ParseError for syntactical errors */ - private def crawlCstDecl(start: Int, parentURI: URI) : (CstDeclBlock, Int) = + private def crawlCstDecl(start: Int, parentURI: URI) : (CstDeclBlock, Int) = { var i = start if (flat.startsWith("%abbrev", i)) { @@ -486,15 +486,15 @@ class FileCrawler(file : File) { val url = new URI(Catalog.getPath(file) + "#" + position) return (CstDeclBlock(parentURI ? cstName, url, cstName, position), endsAt + 1) } - - + + /** Reads a structure declaration. * @param start the position of the initial % from %struct * @param parentURI the URI of the parent module * @param currentNS the current namespace * @return Pair(a StrDecl containing the information from the structure declaration, position after the block) * @throws ParseError for syntactical errors */ - private def crawlStrDecl(start: Int, parentURI: URI, currentNS: Option[URI], prefixes: LinkedHashMap[String,URI]) : (StrDeclBlock, Int) = + private def crawlStrDecl(start: Int, parentURI: URI, currentNS: Option[URI], prefixes: LinkedHashMap[String,URI]) : (StrDeclBlock, Int) = { var i = start val children = new MutableList[AssignmentBlock] () @@ -517,7 +517,7 @@ class FileCrawler(file : File) { i = positionAfterDomain i = skipwscomments(i) } - + if (flat.codePointAt(i) == '=') { i += 1 i = skipwscomments(i) @@ -532,27 +532,27 @@ class FileCrawler(file : File) { } else if (domain.isEmpty) throw ParseError(toPair(start, lineStarts) + ": error: structure has no definiens and its domain is not specified") - - + + val endsAt = skipUntilDot(i) - 1 // skip over %open statement val position = new Position(toPair(start, lineStarts), toPair(endsAt, lineStarts)) val url = new URI(Catalog.getPath(file) + "#" + position) return (StrDeclBlock(parentURI ? structureName, url, structureName, children, domain, position), endsAt + 1) } - - + + /** Reads a constant assignment. * @param start the position of the first character in the constant identifier * @param parentURI the URI of the parent module * @return Pair(a CstAssignment containing the information from the constant assignment, position after the block) * @throws ParseError for syntactical errors */ - private def crawlCstAssignment(start: Int, parentURI: URI) : (CstAssignmentBlock, Int) = + private def crawlCstAssignment(start: Int, parentURI: URI) : (CstAssignmentBlock, Int) = { var i = start val (cstName, positionAfter) = crawlIdentifier(i) // read constant name val constantName = cstName.replaceAll("\\Q.\\E", "/") i = positionAfter - + i = expectNext(i, ":=", toPair(i, lineStarts) + ": error: ':=' expected") i += ":=".length val endsAt = skipUntilDot(i) - 1 @@ -560,14 +560,14 @@ class FileCrawler(file : File) { val url = new URI(Catalog.getPath(file) + "#" + position) return (CstAssignmentBlock(parentURI ? constantName, url, constantName, position), endsAt + 1) } - - + + /** Reads a structure assignment. * @param start the position of the initial % from %struct * @param parentURI the URI of the parent module * @return Pair(a StrAssignment containing the information from the structure assignment, position after the block) * @throws ParseError for syntactical errors */ - private def crawlStrAssignment(start: Int, parentURI: URI) : (StrAssignmentBlock, Int) = + private def crawlStrAssignment(start: Int, parentURI: URI) : (StrAssignmentBlock, Int) = { var i = start if (i + "%struct".length + 2 >= flat.length) @@ -577,7 +577,7 @@ class FileCrawler(file : File) { val (strName, positionAfter) = crawlIdentifier(i) // read structure name val structureName = strName.replaceAll("\\Q.\\E", "/") i = positionAfter - + i = expectNext(i, ":=", toPair(i, lineStarts) + ": error: ':=' expected") i += ":=".length val endsAt = skipUntilDot(i) - 1 @@ -585,13 +585,13 @@ class FileCrawler(file : File) { val url = new URI(Catalog.getPath(file) + "#" + position) return (StrAssignmentBlock(parentURI ? structureName, url, structureName, position), endsAt + 1) } - - + + // ------------------------------- module-level ------------------------------- - - + + /** Reads a theory body - * @param start the position of the opening { + * @param start the position of the opening { * @param parentURI the URI of the enclosing signature * @param children list of constant and structure declarations, updated with the information read in the body * @param deps set of dependencies, updated with the information read in the body @@ -634,7 +634,7 @@ class FileCrawler(file : File) { val (importName, positionAfter) = crawlIdentifier(i) // read import name deps += moduleToAbsoluteURI(i, importName, currentNS, prefixes) i = positionAfter - i = skipUntilDot(i) // skip over the optional %open statement + i = skipUntilDot(i) // skip over the optional %open statement } else if (flat.startsWith("%struct", i)) { // Read structure declaration @@ -652,22 +652,22 @@ class FileCrawler(file : File) { } else if (flat.codePointAt(i) == '}') return i + 1 - else + else throw ParseError(toPair(i, lineStarts) + ": error: unknown declaration in signature body") keepComment = None // reset the last semantic comment stored i = skipwscomments(i) // check whether there is a new semantic comment } return i } - - + + /** Reads a theory. * @param start the position of the initial '%' * @param currentNS the current namespace * @param prefixes the mapping from aliases to namespaces * @return Pair(a SigBlock containing the information from the theory, position after the block) * @throws ParseError for syntactical errors */ - private def crawlSigBlock(start: Int, currentNS: Option[URI], prefixes: LinkedHashMap[String,URI]) : (SigBlock, Int) = + private def crawlSigBlock(start: Int, currentNS: Option[URI], prefixes: LinkedHashMap[String,URI]) : (SigBlock, Int) = { var i = skipwscomments(start + "%sig".length) // jump over %sig val (sigName, positionAfter) = crawlIdentifier(i) @@ -676,20 +676,20 @@ class FileCrawler(file : File) { i = expectNext(i, "=", toPair(start, lineStarts) + ": error: signature does not have '=' after its name") i += 1 // jump over "=" i = expectNext(i, "{", toPair(start, lineStarts) + ": error: signature does not have an initial '{'") - + var children = new MutableList[DeclBlock] () var deps = LinkedHashSet[URI] () i = crawlSigBody(i, uri, children, deps, currentNS, prefixes) // read the { body } of the signature - + val endsAt = expectNext(i, ".", toPair(start, lineStarts) + ": error: signature does not end with a dot") val position = new Position(toPair(start, lineStarts), toPair(endsAt, lineStarts)) val url = new URI(Catalog.getPath(file) + "#" + position) return (new SigBlock(uri, url, sigName, children, deps, position), endsAt + 1) } - - + + /** Reads a link (view or complex structure) body - * @param start the position of the opening { + * @param start the position of the opening { * @param parentURI the URI of the enclosing view or structure declaration * @param children list of constant and structure assignments, updated with the information read in the body * @param deps set of dependencies, updated with the information read in the body @@ -746,8 +746,8 @@ class FileCrawler(file : File) { } return i } - - + + /** Reads a sequence of linespace-separated signature references, ended by either =, -> or a non-identifier-part-character * @param start the position of the first character in the sequence * @param currentNS the current namespace @@ -772,69 +772,69 @@ class FileCrawler(file : File) { val endsAt = i return (sigs, endsAt) } - - + + /** Reads a view. * @param start the position of the initial '%' * @param currentNS the current namespace * @param prefixes the mapping from aliases to namespaces * @return Pair(a ViewBlock containing the information from the view, position after the block) * @throws ParseError for syntactical errors */ - private def crawlViewBlock(start: Int, currentNS: Option[URI], prefixes: LinkedHashMap[String,URI]) : (ViewBlock, Int) = + private def crawlViewBlock(start: Int, currentNS: Option[URI], prefixes: LinkedHashMap[String,URI]) : (ViewBlock, Int) = { var i = start + "%view".length // jump over %view i = skipws(i) if (flat.startsWith("%implicit", i)) i = skipws(i + "%implicit".length) - + val children = new MutableList[AssignmentBlock] () val deps = LinkedHashSet[URI] () - + i = skipwscomments(i) - + val (viewName, positionAfter) = crawlIdentifier(i) // read view name val uri = moduleToAbsoluteURI(i, viewName, currentNS, prefixes) i = positionAfter // jump over name - + i = expectNext(i, ":", toPair(start, lineStarts) + ": error: view does not have ':' after its name") i += 1 // jump over ":" - + i = skipwscomments(i) - + val (viewDomain, positionAfterDomain) = crawlIdentifier(i) // read view domain val viewDomainURI = moduleToAbsoluteURI(i, viewDomain, currentNS, prefixes) deps += viewDomainURI i = positionAfterDomain // jump over domain - + i = "->".length + expectNext(i, "->", toPair(start, lineStarts) + ": error: view does not have '->' between domain and codomain") - + i = skipwscomments(i) - + val (viewCodomain, positionAfterCodomain) = crawlSignatureUnion(i, currentNS, prefixes) // read view codomain deps ++= viewCodomain.toTraversable i = positionAfterCodomain // jump over codomain - + i = expectNext(i, "=", toPair(start, lineStarts) + ": error: view does not have '=' after its name") i += 1 // jump over "=" i = expectNext(i, "{", toPair(start, lineStarts) + ": error: view does not have an initial '{'") - + i = crawlLinkBody(i, uri, children, deps, currentNS, prefixes, true) // read the { body } of the view - + i = expectNext(i, ".", toPair(start, lineStarts) + ": error: view does not end with a dot") val endsAt = i val position = new Position(toPair(start, lineStarts), toPair(endsAt, lineStarts)) val url = new URI(Catalog.getPath(file) + "#" + position) - + return (new ViewBlock(uri, url, viewName, children, deps, viewDomainURI, viewCodomain, position), endsAt + 1) } - - + + // ------------------------------- auxiliary methods ------------------------------- - - + + private def min(a: Int, b: Int) = if (a <= b) a else b - - + + /** Convert a module name to its URI. Only namespace prefixes are checked. * @param start position of the first character of the module name (for error reporting) * @param moduleName the module name as a string @@ -842,7 +842,7 @@ class FileCrawler(file : File) { * @param prefixes map from aliases to remote absolute URIs * @return the absolute URI of the module * @throws ParseError if the module name has a prefix and the prefix is not a valid namespace alias, or if the module name has no prefix and the current namespace is not defined */ - private def moduleToAbsoluteURI(start: Int, moduleName: String, currentNS: Option[URI], prefixes: LinkedHashMap[String,URI]) : URI = { + private def moduleToAbsoluteURI(start: Int, moduleName: String, currentNS: Option[URI], prefixes: LinkedHashMap[String,URI]) : URI = { // the URI of the module is *not* used to compute the absolute URI of its dependencies // Replace dots with question marks val relativeURI : String = moduleName.trim().replaceAll("\\056", "?") @@ -860,15 +860,15 @@ class FileCrawler(file : File) { val realURI = prefixes.get(prefix).get return new URI(realURI.toString() + relativeURI.substring(j)) } - - + + /** Get the (line, column) that represents the same position as the given one-dimensional coordinate * @param index the one-dimensional coordinate to be transformed into two-dimensional * @param lineStarts array of pairs . All indexes are 0-based. * @return Pair(line, column) */ - def toPair(index: Int, lineStarts: ArraySeq[(Int, Int)]) : (Int,Int) = + def toPair(index: Int, lineStarts: ArraySeq[(Int, Int)]) : (Int,Int) = { val pair = lineStarts.filter(p => (p._1 <= index)).last (pair._2, index - pair._1) // the column may be the bogus space character at the end of the line } -} \ No newline at end of file +} diff --git a/src/lfcatalog/src/info/kwarc/mmt/twelf/run.scala b/src/lfcatalog/src/info/kwarc/mmt/twelf/run.scala index 7b101cfdad..ad40e767dd 100644 --- a/src/lfcatalog/src/info/kwarc/mmt/twelf/run.scala +++ b/src/lfcatalog/src/info/kwarc/mmt/twelf/run.scala @@ -9,37 +9,37 @@ import scala.collection.mutable.HashSet /** Run the web server and console input */ object Run { private val usage = """Usage: java -jar lfcatalog.jar (--port )? (location|+inclusion|-exclusion)* - + location === absolute path to a file or directory inclusion === name exclusion === name name === file or directory name pattern, without its path. Star is the only special character and matches any sequence of characters. - + A folder is crawled iff it doesn't match any exclusion pattern. A file is crawled iff it matches at least one inclusion pattern, but no exclusion pattern. However, if no inclusion patterns are provided, only the second condition remains. The default port is 8080 on localhost.""" - + /** Port on which the server runs. Default value is 8080 */ private var port = 8080 - + def main(args : Array[String]) { - + // parse program arguments var patternsAndLocations : Array[String] = args val locations = new HashSet[String] () val inclusions = new HashSet[String] () val exclusions = new HashSet[String] () - if (!args.isEmpty) { + if (!args.isEmpty) { // read the optional --port argument if (args.head == "--port") - if (args.length < 2) { + if (args.length < 2) { println("error: port number expected\n\n" + usage); sys.exit(1) } else { try { port = Integer.parseInt(args(1)) } catch { case _: Exception => println("error: port number expected\n\n" + usage); sys.exit(1) } patternsAndLocations = patternsAndLocations.drop(2) - } + } // read the patterns and locations for (s <- patternsAndLocations) if (s.startsWith("-")) // an exclusion pattern @@ -48,14 +48,14 @@ object Run { inclusions += s.drop(1) else locations += s // a location } - + if (inclusions.isEmpty) inclusions += "*.elf" if (exclusions.isEmpty) exclusions += ".svn" - + // the main storage and controller (this also starts background threads) var catalog = new Catalog(locations, inclusions, exclusions, port, true) port = catalog.init - + // accept console input while (true) { val input = scala.io.StdIn.readLine.trim diff --git a/src/lfcatalog/src/info/kwarc/mmt/twelf/uri.scala b/src/lfcatalog/src/info/kwarc/mmt/twelf/uri.scala index e86fd56c64..a87d5a213a 100644 --- a/src/lfcatalog/src/info/kwarc/mmt/twelf/uri.scala +++ b/src/lfcatalog/src/info/kwarc/mmt/twelf/uri.scala @@ -9,23 +9,23 @@ case class URI(var uri : java.net.URI) { * @throws java.net.URISyntaxException if the URI violates RFC 2396 or RFC 3986 */ def this(s : String) = this(URI.encode(s)) - + /** Create an valid URI where the illegal or non-ascii character in path, query and fragment are quoted * @return a valid, %-encoded URI - * @throws java.net.URISyntaxException if both a scheme and a path are given but the path is relative, if the URI string constructed from the given components violates RFC 2396, or if the authority component of the string is present but cannot be parsed as a server-based authority + * @throws java.net.URISyntaxException if both a scheme and a path are given but the path is relative, if the URI string constructed from the given components violates RFC 2396, or if the authority component of the string is present but cannot be parsed as a server-based authority */ def this(scheme : String, authority : String, path : String, query : String) = this(new java.net.URI(scheme, authority, path, query, null)) - + /** Return the unencoded URI */ override def toString = java.net.URLDecoder.decode(uri.toString.replace("+", "%2B"), "UTF-8") - + private def up(s : String) : String = { - val p = s.lastIndexOf("/") + val p = s.lastIndexOf("/") if (p == -1) "" else if (p == 0) "/" else s.substring(0,p) } - + def /(n : String) : URI = new URI(uri.toString + "/" + n) def ?(n : String) : URI = new URI(uri.toString + "?" + n) def ^ : URI = new URI(uri.getScheme, uri.getAuthority, up(uri.getPath), null) @@ -71,4 +71,4 @@ object testme extends Application { println(s + " " + u.toString) println(isTaken(8080)) -}*/ \ No newline at end of file +}*/ diff --git a/src/lfcatalog/src/info/kwarc/mmt/twelf/util.scala b/src/lfcatalog/src/info/kwarc/mmt/twelf/util.scala index 5d04fc4bab..e0cabc34f8 100644 --- a/src/lfcatalog/src/info/kwarc/mmt/twelf/util.scala +++ b/src/lfcatalog/src/info/kwarc/mmt/twelf/util.scala @@ -46,7 +46,7 @@ object Time { /** For synchronization of update operations */ -object ConflictGuard +object ConflictGuard /** Checks if a port is used @@ -73,13 +73,13 @@ object isTaken { /** Get a stream to a resource within the JAR file. If it's not found in the JAR, then it looks into the file system - * @param path to the resource, starting with a slash, e.g. /some-path/resource.txt. - * If the resource is in the JAR, then the JAR must look like + * @param path to the resource, starting with a slash, e.g. /some-path/resource.txt. + * If the resource is in the JAR, then the JAR must look like * jar-name.jar/some-path/resource.txt * If the resource is a separate file and the code is run from outside any JAR, then the folder structure must look like * compiled-folder * |--top-level-package-name/../class-files - * |--some-path/resource.txt + * |--some-path/resource.txt * @param encoding the encoding of the resource file * @return Some(stream to the resource) if found, None otherwise. **The caller must close the stream after reading!** * @throws EncodingException(message) if the file is not in the given encoding diff --git a/src/lfcatalog/src/info/kwarc/mmt/twelf/webserver.scala b/src/lfcatalog/src/info/kwarc/mmt/twelf/webserver.scala index 6a07d5a251..a3ece2acd0 100644 --- a/src/lfcatalog/src/info/kwarc/mmt/twelf/webserver.scala +++ b/src/lfcatalog/src/info/kwarc/mmt/twelf/webserver.scala @@ -18,26 +18,28 @@ import scala.xml._ * @param catalog the main controller and storage * @param port the port on which the server runs */ class WebServer(catalog : Catalog, port : Int) extends HServer { - - override def onMessage(s: String) { - catalog.log(s) - } + + // log all the things + override def error(msg: String, t: Throwable) = catalog.log(msg) + override def warning(msg: String) = catalog.log(msg) + override def info(msg: String) = catalog.log(msg) + /** Administration page, read from jar://resources/admin.html */ var adminHtml : Option[scala.xml.Elem] = None - + /** Error page returned by the server */ val adminError = "cannot find jar://server-resources/admin.html." - + /** Readme page, read from jar://resources/readme.txt */ var readmeText : Option[String] = None - + /** Error page returned by the server */ val readmeError = "cannot find jar://server-resources/readme.html." - + // Read jar://resources/admin.html try { loadResource("/server-resources/admin.html", "UTF-8") match { - case Some(bufferedSource) => + case Some(bufferedSource) => try { adminHtml = Option(scala.xml.parsing.XhtmlParser(bufferedSource).head.asInstanceOf[scala.xml.Elem]) } catch { @@ -47,26 +49,26 @@ class WebServer(catalog : Catalog, port : Int) extends HServer { } finally { bufferedSource.close // close the file, since scala.io.Source doesn't close it } - case None => catalog.log("warning: /server-resources/admin.html does not exist") + case None => catalog.log("warning: /server-resources/admin.html does not exist") } } catch { case EncodingException(msg) => catalog.log(msg); sys.exit(1) } - + // Read jar://resources/readme.txt try { loadResource("/server-resources/readme.txt", "UTF-8") match { - case Some(bufferedSource) => + case Some(bufferedSource) => readmeText = Option(bufferedSource.getLines.toArray.mkString("\n")) bufferedSource.close // close the file, since scala.io.Source doesn't close it - case None => catalog.log("warning: /server-resources/readme.txt does not exist") + case None => catalog.log("warning: /server-resources/readme.txt does not exist") } } catch { case EncodingException(msg) => catalog.log(msg); sys.exit(1) } - + override def name = "lfserver" //override def writeBufSize = 16*1024 override def tcpNoDelay = true // make this false if you have extremely frequent requests @@ -81,15 +83,15 @@ class WebServer(catalog : Catalog, port : Int) extends HServer { protected def talkPoolSize = 4 protected def talkQueueSize = Int.MaxValue protected def selectorPoolSize = 2 - - + + /** A recursive function that replaces: * 1. with the bullet list of locations - * 2. with the bullet list of inclusion patterns + * 2. with the bullet list of inclusion patterns * 3. with the bullet list of exclusion patterns */ private def updateLocations(node : Node) : Node = node match { - case => {
    { catalog.locations.flatMap(f => -
  • + case => {
      { catalog.locations.flatMap(f => +
    • @@ -101,15 +103,15 @@ class WebServer(catalog : Catalog, port : Int) extends HServer { case Elem(a, b, c, d, ch @_*) => Elem(a, b, c, d, true, ch.map(updateLocations) : _*) case other => other } - - + + /** Request handler */ protected class RequestHandler extends HApp { //override def buffered = true def resolve(req : HReqData) : Option[HLet] = { if (req.uriPath != "favicon.ico") catalog.log(Time + "Query: " + req.uriPath + "?" + req.query + " ") - + val response : Option[HLet] = req.uriPath match { case "favicon.ico" => Some(TextResponse("", None)) // ignore the browser's request for favicon.ico case "help" | "" => { @@ -119,7 +121,7 @@ class WebServer(catalog : Catalog, port : Int) extends HServer { if (req.query == "") { Some(HTMLResponse(adminHtml.map(updateLocations).getOrElse(adminError).toString)) } - else if (req.query.startsWith("addLocation=")) { ConflictGuard.synchronized { + else if (req.query.startsWith("addLocation=")) { ConflictGuard.synchronized { try { catalog.addStringLocation(java.net.URLDecoder.decode(req.query.substring("addLocation=".length), "UTF-8")) } catch { @@ -127,7 +129,7 @@ class WebServer(catalog : Catalog, port : Int) extends HServer { } Some(HTMLResponse(adminHtml.map(updateLocations).getOrElse(adminError).toString)) }} - else if (req.query.startsWith("deleteLocation=")) { ConflictGuard.synchronized { + else if (req.query.startsWith("deleteLocation=")) { ConflictGuard.synchronized { try { catalog.deleteStringLocation(java.net.URLDecoder.decode(req.query.substring("deleteLocation=".length), "UTF-8")) } catch { @@ -135,17 +137,17 @@ class WebServer(catalog : Catalog, port : Int) extends HServer { } Some(HTMLResponse(adminHtml.map(updateLocations).getOrElse(adminError).toString)) }} - else if (req.query.startsWith("addInclusion=")) { ConflictGuard.synchronized { + else if (req.query.startsWith("addInclusion=")) { ConflictGuard.synchronized { catalog.addInclusion(java.net.URLDecoder.decode(req.query.substring("addInclusion=".length), "UTF-8")) Some(HTMLResponse(adminHtml.map(updateLocations).getOrElse(adminError).toString)) }} - else if (req.query.startsWith("addExclusion=")) { ConflictGuard.synchronized { + else if (req.query.startsWith("addExclusion=")) { ConflictGuard.synchronized { catalog.addExclusion(java.net.URLDecoder.decode(req.query.substring("addExclusion=".length), "UTF-8")) Some(HTMLResponse(adminHtml.map(updateLocations).getOrElse(adminError).toString)) }} else Some(TextResponse("Invalid query: " + req.query, None)) } - case "crawlAll" => { ConflictGuard.synchronized { + case "crawlAll" => { ConflictGuard.synchronized { catalog.crawlAll Some(HTMLResponse(adminHtml.map(updateLocations).getOrElse(adminError).toString)) }} @@ -315,7 +317,7 @@ class WebServer(catalog : Catalog, port : Int) extends HServer { response } } - + /** A text response that the server sends back to the browser * @param text the message that is sent in the HTTP body * @param header optionally, a custom header tag, given as Pair(tag, content) that is added to the HTTP header @@ -340,7 +342,7 @@ class WebServer(catalog : Catalog, port : Int) extends HServer { tk.write(out) } } - + /** An HTML response that the server sends back to the browser * @param text the HTML message that is sent in the HTTP body */ @@ -352,4 +354,4 @@ class WebServer(catalog : Catalog, port : Int) extends HServer { .write(out) } } -} \ No newline at end of file +} diff --git a/src/marpa-mmt/src/info/kwarc/mmt/marpa/Grammar.scala b/src/marpa-mmt/src/info/kwarc/mmt/marpa/Grammar.scala index 3056da144a..00ca83e772 100644 --- a/src/marpa-mmt/src/info/kwarc/mmt/marpa/Grammar.scala +++ b/src/marpa-mmt/src/info/kwarc/mmt/marpa/Grammar.scala @@ -98,15 +98,15 @@ object Grammar { val content: List[String] = markers.map( x ⇒ x match { - // NOTE: #seq_ is used to indicate whether the Delim is - // inside a sequence argument, since if it is in one - // the text inside the Delim should never be empty - // to avoid infinite left recursion + // NOTE: #seq_ is used to indicate whether the Delim is + // inside a sequence argument, since if it is in one + // the text inside the Delim should never be empty + // to avoid infinite left recursion case Delim(text) ⇒ addRule(Delim("#seq_" + text)) case _ ⇒ addRule(x) }) - if (!(content.length == 1 && content(0).startsWith("argRule")) // do not include rules that only have one argRule (creates cycles) + if (!(content.length == 1 && content(0).startsWith("argRule")) // do not include rules that only have one argRule (creates cycles) ) { rules = rules | Set((Rule(uniqueName, "topLevel" :: content))) //uniqueness of top level notations is assumed } else { @@ -114,7 +114,7 @@ object Grammar { } if (!isOmitted(uniqueName)) { eventList ::= "event '" + uniqueName + "' = completed " + uniqueName - } + } } //returns the name of the rule, adds the rule to the Set[Rule] only if it is not already there @@ -240,7 +240,7 @@ object Grammar { text = " " } - if (text == "⁢" //unicode + if (text == "⁢" //unicode && flag == "") { //handling the invisible unicode char used for function application val v1 = createRule("empty" :: Nil) val v2 = createRule("mnB" :: text.toString :: "mnE" :: Nil) @@ -394,9 +394,9 @@ object Grammar { } result - // case Subs(nr,precOp) => addRule(Arg(nr,precOp)) - // case SqrtMarker(ml) => - // createRule("msqrtB"::ml.map(addRule):::"msqrtE"::Nil) + // case Subs(nr,precOp) => addRule(Arg(nr,precOp)) + // case SqrtMarker(ml) => + // createRule("msqrtB"::ml.map(addRule):::"msqrtE"::Nil) case _ ⇒ println("ERROR: TODO Marker: " + marker.toString) "'TODO'" @@ -485,7 +485,7 @@ object Grammar { } } - //creates the grammar as a List[String] by adding a manually written prefix that gives the Grammar + //creates the grammar as a List[String] by adding a manually written prefix that gives the Grammar //an overall shape and also includes presentation MathML parsing //the actual grammar is assembled in Perl by inserting '\n' in between the elements of the List. def getMarpaGrammar: List[String] = { @@ -626,7 +626,7 @@ object Grammar { val result = grammarCore ::: Notation ::: extractedRules //::: eventList println(omittedRulesCounter + " rules were omitted (would create cycles/other reasons)") - cleanup() + cleanup() result } @@ -643,4 +643,4 @@ object Grammar { index = 0; omittedRulesCounter = 0; } -} \ No newline at end of file +} diff --git a/src/marpa-mmt/src/info/kwarc/mmt/marpa/MarpaServerPlugin.scala b/src/marpa-mmt/src/info/kwarc/mmt/marpa/MarpaServerPlugin.scala index a9153409b8..46b96903e3 100644 --- a/src/marpa-mmt/src/info/kwarc/mmt/marpa/MarpaServerPlugin.scala +++ b/src/marpa-mmt/src/info/kwarc/mmt/marpa/MarpaServerPlugin.scala @@ -4,15 +4,15 @@ package info.kwarc.mmt.marpa * ------------------------------------------ * Toloaca Ion * ------------------------------------------ - * General information: - * New notations are written in sTeX, afterwards LaTeXML is used to convert those to .omdoc , + * General information: + * New notations are written in sTeX, afterwards LaTeXML is used to convert those to .omdoc , * then MMT is used to parse the .omdoc documents and to store the relevant notations. * - * Purpose: - * The code below uses the notations stored in MMT as Markers (Scala datatypes) to create a Marpa + * Purpose: + * The code below uses the notations stored in MMT as Markers (Scala datatypes) to create a Marpa * grammar and make it available via a post request. * - * Details: + * Details: * To convert from Markers to a Marpa grammar an intermediate format is used (List[String]). * Although the format might have been omitted, using tokenized strings make the recursion and * the transformation from Markers to the grammar easier, and creating unique rules also becomes easier. @@ -98,7 +98,7 @@ class MarpaGrammarGenerator extends ServerExtension("marpa") with Logger { } } - //The post request response is defined here + //The post request response is defined here def getGrammarResponse(request: ServerRequest): ServerResponse = val reqBody = request.body val notations = controller.library.getModules flatMap { @@ -123,7 +123,7 @@ class MarpaGrammarGenerator extends ServerExtension("marpa") with Logger { val grammarAsStringList = Grammar.getMarpaGrammar.map(x ⇒ info.kwarc.mmt.api.utils.JSONString(x)) val resp = info.kwarc.mmt.api.utils.JSONArray(grammarAsStringList: _*) - // val params = reqBody.asJSON + // val params = reqBody.asJSON ServerResponse.JsonResponse(resp) } @@ -294,8 +294,8 @@ class MarpaGrammarGenerator extends ServerExtension("marpa") with Logger { }) /* * x => OMI(x) for integers - * => OMV(x) - * s => OMS(s.toPath) + * => OMV(x) + * s => OMS(s.toPath) * CML (apply/csymbol) => eventually literal OMLit(CML) or OMFOREIGN */ } @@ -397,4 +397,4 @@ class MarpaGrammarGenerator extends ServerExtension("marpa") with Logger { case _ ⇒ throw ServerError("Invalid JSON " + bodyS) } } -} \ No newline at end of file +} diff --git a/src/marpa-mmt/src/info/kwarc/mmt/marpa/SemanticTree.scala b/src/marpa-mmt/src/info/kwarc/mmt/marpa/SemanticTree.scala index 4cc9e4695e..b0b75e9de1 100644 --- a/src/marpa-mmt/src/info/kwarc/mmt/marpa/SemanticTree.scala +++ b/src/marpa-mmt/src/info/kwarc/mmt/marpa/SemanticTree.scala @@ -86,7 +86,7 @@ object SemanticTree { case class RawString(value: String) extends ParseTree { override def toCML: List[String] = { - List(value) + List(value) } } @@ -139,7 +139,7 @@ object SemanticTree { list.foreach((variant) ⇒ println(" Variant = " + variant.toString)) } } - case _ => + case _ => } println("END OF INPUT PARSES") val CMLlist = inputParses.toCML.toSet.toList map java.net.URLDecoder.decode// Get unique parses @@ -231,7 +231,7 @@ object SemanticTree { println("Invalid argument type: " + argType) } } - } // substringList foreach + } // substringList foreach } // arguments foreach val term = grammarGenerator.doNotationTerm( grammarGenerator.pairIndexNotation(ruleNr)._1._1, @@ -318,7 +318,7 @@ object SemanticTree { // Remove useless toplevel mrow if (input.startsWith("%3Cmrow%3E") && input.endsWith("%3C%2Fmrow%3E")) { return sendGetNotationPosRequest(input.substring(10, input.length - 13)) - } + } // Memoization val vals = sendGetNotationPosRequestMemo if (vals.contains(input)) { @@ -336,12 +336,12 @@ object SemanticTree { // List(For each argument, for each argument part, one of the possible parses) // List(List(List(1,2),List(3)), List(List(4,5))) => // ListArg(ListPart(ListParse(1,2),ListParse(3)), ListPart(ListParse(4,5))) => - /* ListPossibilities( + /* ListPossibilities( ListArg( ListPart(1,3), ListPart(4) ) ListArg( ListPart(1,3), ListPart(5) ) ListArg( ListPart(2,3), ListPart(4) ) ListArg( ListPart(2,3), ListPart(5) ) - ) + ) */ /* ListPossibilities( Nil ) */ @@ -369,4 +369,4 @@ object SemanticTree { case xs :: rss ⇒ for (x ← xs; cs ← combs(rss)) yield x :: cs } -} \ No newline at end of file +} diff --git a/src/mmt-api/resources/help-text/about.txt b/src/mmt-api/resources/help-text/about.txt deleted file mode 100644 index f8e68ccfdf..0000000000 --- a/src/mmt-api/resources/help-text/about.txt +++ /dev/null @@ -1 +0,0 @@ -See documentation in https://svn.kwarc.info/repos/MMT/doc/html/index.html diff --git a/src/mmt-api/resources/help-text/help.txt b/src/mmt-api/resources/help-text/help.txt index 71124a6aad..e3a3f4deed 100644 --- a/src/mmt-api/resources/help-text/help.txt +++ b/src/mmt-api/resources/help-text/help.txt @@ -1,38 +1,7 @@ -usage: - mmt [--help|--about] [--shell|--keepalive|--noshell] [--file FILENAME] [--mbt FILENAME] [--send PORT] [COMMANDS] +This is the MMT shell, you may enter actions to be evaluated. +Type 'show help' to see this message at any point, 'show help topics' to get a +list of available help topics and 'show mmt' for information about the version +of the mmt system you have installed. +For more details, you may refer to the online help available at: -the MMT shell script - -general arguments: - -h, --help show this help message and exit. - -a, --about print some information about MMT. - --usage show usage message for specific 'make' COMMANDS - --help-command currently identical to --usage - -commands and files to process: - COMMANDS Semicolon ( ; ) separated commands to be interpreted by MMT. If a command fails, exit - immediately with code 2. Type "help" inside the shell for a list of commands or look at the - documentation for available commands. - --send PORT send COMMANDS to an already running MMT Instance listening at PORT and exit immediately - (even if a different termination behaviour is specified.) - --file FILENAME load mmt-style commands from FILE before interpreting COMMANDS. - (this option may be repeated multiple times.) - --mbt FILENAME load scala-style commands from FILE before interpreting COMMANDS. - (this option may be repeated multiple times.) - -termination behaviour: - -The default exit behaviour is to terminate immediately after COMMANDS have been executed. If no arguments are given to -MMT, it will start an interactive shell for the user to enter commands. The default behaviour of MMT can be overwritten -with the following arguments. - - -i, --shell execute COMMANDS and take further commands on the MMT shell. - (this is the default if no arguments are provided.) - -w, --keepalive execute COMMANDS and terminate only after all threads have finished. - (no MMT shell will be started.) - -w, --noshell same as --keepalive (for backwards compatibility) - -By default, MMT will terminate with status code 0. If parsing of arguments fails, MMT will terminate prematurely with -status code 1. If an uncaught exception occurs in the main thread, MMT will exit with status code 2. - -note: for long options arguments can also be given using "=", i.e. --file=FILENAME. +https://uniformal.github.io/doc/applications/shell.html \ No newline at end of file diff --git a/src/mmt-api/resources/help-text/shelltitle.txt b/src/mmt-api/resources/help-text/shelltitle.txt deleted file mode 100644 index 403d901fba..0000000000 --- a/src/mmt-api/resources/help-text/shelltitle.txt +++ /dev/null @@ -1,2 +0,0 @@ -This is the MMT shell. -See https://uniformal.github.io/apidoc/#info.kwarc.mmt.api.frontend.Action for the available commands. diff --git a/src/mmt-api/resources/help-text/usage.txt b/src/mmt-api/resources/help-text/usage.txt index 36ccbf1491..f15983e286 100644 --- a/src/mmt-api/resources/help-text/usage.txt +++ b/src/mmt-api/resources/help-text/usage.txt @@ -1,2 +1,39 @@ usage: - mmt [--help|--about] [--shell|--keepalive|--noshell] [--file FILENAME] [--mbt FILENAME] [--send PORT] [COMMANDS] + mmt [--help|--about|--version] [--shell|--keepalive|--noshell] [--file FILENAME] [--mbt FILENAME] [--send PORT] [COMMANDS] + +the MMT shell script + +general arguments: + -h, --help show this help message and exit. + -a, --about print some information about MMT. + -v, --version alias of --about + --usage show usage message for specific 'make' COMMANDS + --help-command currently identical to --usage + +commands and files to process: + COMMANDS Semicolon ( ; ) separated commands to be interpreted by MMT. If a command fails, exit + immediately with code 2. Type "help" inside the shell for a list of commands or look at the + documentation for available commands. + --send PORT send COMMANDS to an already running MMT Instance listening at PORT and exit immediately + (even if a different termination behaviour is specified.) + --file FILENAME load mmt-style commands from FILE before interpreting COMMANDS. + (this option may be repeated multiple times.) + --mbt FILENAME load scala-style commands from FILE before interpreting COMMANDS. + (this option may be repeated multiple times.) + +termination behaviour: + +The default exit behaviour is to terminate immediately after COMMANDS have been executed. If no arguments are given to +MMT, it will start an interactive shell for the user to enter commands. The default behaviour of MMT can be overwritten +with the following arguments. + + -i, --shell execute COMMANDS and take further commands on the MMT shell. + (this is the default if no arguments are provided.) + -w, --keepalive execute COMMANDS and terminate only after all threads have finished. + (no MMT shell will be started.) + -w, --noshell same as --keepalive (for backwards compatibility) + +By default, MMT will terminate with status code 0. If parsing of arguments fails, MMT will terminate prematurely with +status code 1. If an uncaught exception occurs in the main thread, MMT will exit with status code 2. + +note: for long options arguments can also be given using "=", i.e. --file=FILENAME. diff --git a/src/mmt-api/resources/help-text/usage_short.txt b/src/mmt-api/resources/help-text/usage_short.txt new file mode 100644 index 0000000000..0554a434f0 --- /dev/null +++ b/src/mmt-api/resources/help-text/usage_short.txt @@ -0,0 +1,2 @@ +usage: + mmt [--help|--about|--version] [--shell|--keepalive|--noshell] [--file FILENAME] [--mbt FILENAME] [--send PORT] [COMMANDS] diff --git a/src/mmt-api/resources/mmt-web/browse.html b/src/mmt-api/resources/mmt-web/browse.html index bfc616029c..513fb7fa44 100644 --- a/src/mmt-api/resources/mmt-web/browse.html +++ b/src/mmt-api/resources/mmt-web/browse.html @@ -11,7 +11,7 @@ - + - + @@ -27,7 +30,7 @@ - +
      × @@ -38,6 +41,8 @@
      +
      +