Skip to content

Commit 1f6ba72

Browse files
committed
improvement: Support only one type of using directives
It seems that we still support multiple ways of declaring using directives, which should be removed before 1.0.x. It's also needed for SIP so that it's clear what can be accepted by the SIP commitee.
1 parent 36dd3af commit 1f6ba72

File tree

7 files changed

+41
-170
lines changed

7 files changed

+41
-170
lines changed

modules/build/src/main/scala/scala/build/preprocessing/ExtractedDirectives.scala

Lines changed: 19 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,12 @@ import scala.collection.mutable
1818
import scala.jdk.CollectionConverters.*
1919

2020
case class ExtractedDirectives(
21-
offset: Int,
2221
directives: Seq[StrictDirective],
2322
positions: Option[DirectivesPositions]
2423
) {
2524
@targetName("append")
2625
def ++(other: ExtractedDirectives): ExtractedDirectives =
27-
ExtractedDirectives(offset, directives ++ other.directives, positions)
26+
ExtractedDirectives(directives ++ other.directives, positions)
2827
}
2928

3029
case class DirectivesPositions(
@@ -35,16 +34,15 @@ case class DirectivesPositions(
3534

3635
object ExtractedDirectives {
3736

38-
def empty: ExtractedDirectives = ExtractedDirectives(0, Seq.empty, None)
37+
def empty: ExtractedDirectives = ExtractedDirectives(Seq.empty, None)
3938

4039
val changeToSpecialCommentMsg =
41-
"Using directive using plain comments are deprecated. Please use a special comment syntax: '//> ...' or '/*> ... */'"
40+
"Using directive using plain comments are deprecated. Please use a special comment syntax: '//> ...'"
4241

4342
def from(
4443
contentChars: Array[Char],
4544
path: Either[String, os.Path],
4645
logger: Logger,
47-
supportedDirectives: Array[UsingDirectiveKind],
4846
cwd: ScopePath,
4947
maybeRecoverOnError: BuildException => Option[BuildException]
5048
): Either[BuildException, ExtractedDirectives] = {
@@ -101,31 +99,24 @@ object ExtractedDirectives {
10199
logger.diagnostic(msg, positions = Seq(position))
102100
}
103101

104-
val usedDirectives =
105-
if (codeDirectives.nonEmpty) {
106-
val msg =
107-
"This using directive is ignored. File contains directives outside comments and those have higher precedence."
108-
reportWarning(
109-
msg,
110-
getDirectives(plainCommentDirectives) ++ getDirectives(specialCommentDirectives)
111-
)
112-
codeDirectives
113-
}
114-
else if (specialCommentDirectives.nonEmpty) {
115-
val msg =
116-
s"This using directive is ignored. $changeToSpecialCommentMsg"
117-
reportWarning(msg, getDirectives(plainCommentDirectives))
118-
specialCommentDirectives
119-
}
120-
else {
121-
reportWarning(changeToSpecialCommentMsg, getDirectives(plainCommentDirectives))
122-
plainCommentDirectives
123-
}
102+
if (codeDirectives.nonEmpty) {
103+
val msg =
104+
"This using directive is ignored. Only using directives starting with //> are supported."
105+
reportWarning(msg, getDirectives(codeDirectives))
106+
}
107+
108+
if (plainCommentDirectives.nonEmpty) {
109+
val msg =
110+
s"This using directive is ignored. $changeToSpecialCommentMsg"
111+
reportWarning(msg, getDirectives(plainCommentDirectives))
112+
}
113+
114+
val usedDirectives = specialCommentDirectives
124115

125116
// All using directives should use just `using` keyword, no @using or require
126117
reportWarning(
127118
"Deprecated using directive syntax, please use keyword `using`.",
128-
getDirectives(usedDirectives).filter(_.getSyntax != UsingDirectiveSyntax.Using),
119+
getDirectives(specialCommentDirectives).filter(_.getSyntax != UsingDirectiveSyntax.Using),
129120
before = false
130121
)
131122

@@ -136,33 +127,13 @@ object ExtractedDirectives {
136127
StrictDirective(k.getPath.asScala.mkString("."), l.asScala.toSeq)
137128
}
138129

139-
val offset =
140-
if (usedDirectives.getKind != UsingDirectiveKind.Code) 0
141-
else usedDirectives.getCodeOffset
142-
if (supportedDirectives.contains(usedDirectives.getKind))
143-
Right(ExtractedDirectives(offset, strictDirectives, directivesPositionsOpt))
144-
else {
145-
val directiveVales =
146-
usedDirectives.getFlattenedMap.values().asScala.toList.flatMap(_.asScala)
147-
val values = DirectiveUtil.concatAllValues(ScopedDirective(
148-
StrictDirective("", directiveVales),
149-
path,
150-
cwd
151-
))
152-
val directiveErrors = new DirectiveErrors(
153-
::(s"Directive '${usedDirectives.getKind}' is not supported in the given context'", Nil),
154-
values.flatMap(_.positions)
155-
)
156-
maybeRecoverOnError(directiveErrors) match {
157-
case Some(e) => Left(e)
158-
case None => Right(ExtractedDirectives.empty)
159-
}
160-
}
130+
Right(ExtractedDirectives(strictDirectives, directivesPositionsOpt))
161131
}
162132
else
163133
maybeCompositeMalformedDirectiveError match {
164134
case Some(e) => Left(e)
165135
case None => Right(ExtractedDirectives.empty)
166136
}
167137
}
138+
168139
}

modules/build/src/main/scala/scala/build/preprocessing/MarkdownCodeBlockProcessor.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ object MarkdownCodeBlockProcessor {
2626
contentChars = cb.body.toCharArray,
2727
path = reportingPath,
2828
logger = logger,
29-
supportedDirectives = UsingDirectiveKind.values(),
3029
cwd = scopePath / os.up,
3130
maybeRecoverOnError = maybeRecoverOnError
3231
)

modules/build/src/main/scala/scala/build/preprocessing/PreprocessingUtil.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,11 @@ object PreprocessingUtil {
3232
BuildException,
3333
(DirectivesProcessorOutput[BuildOptions], Option[DirectivesPositions])
3434
] = either {
35-
val ExtractedDirectives(_, directives0, directivesPositions) =
35+
val ExtractedDirectives(directives0, directivesPositions) =
3636
value(from(
3737
content.toCharArray,
3838
path,
3939
logger,
40-
Array(UsingDirectiveKind.PlainComment, UsingDirectiveKind.SpecialComment),
4140
scopePath,
4241
maybeRecoverOnError
4342
))

modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,6 @@ case object ScalaPreprocessor extends Preprocessor {
209209
contentWithNoShebang.toCharArray,
210210
path,
211211
logger,
212-
UsingDirectiveKind.values(),
213212
scopeRoot,
214213
maybeRecoverOnError
215214
))
@@ -350,7 +349,7 @@ case object ScalaPreprocessor extends Preprocessor {
350349
): Either[BuildException, StrictDirectivesProcessingOutput] = either {
351350
val contentChars = content.toCharArray
352351

353-
val ExtractedDirectives(codeOffset, directives0, directivesPositions) = extractedDirectives
352+
val ExtractedDirectives(directives0, directivesPositions) = extractedDirectives
354353

355354
val updatedOptions = value {
356355
DirectivesProcessor.process(
@@ -380,28 +379,14 @@ case object ScalaPreprocessor extends Preprocessor {
380379

381380
val unusedDirectives = updatedRequirements.unused
382381

383-
val updatedContentOpt =
384-
if (codeOffset > 0) {
385-
val headerBytes = contentChars
386-
.iterator
387-
.take(codeOffset)
388-
.map(c => if (c.isControl) c else ' ')
389-
.toArray
390-
val mainBytes = contentChars.drop(codeOffset)
391-
val updatedContent = new String(headerBytes ++ mainBytes)
392-
if (updatedContent == content) None
393-
else Some(updatedContent)
394-
}
395-
else None
396-
397382
value {
398383
unusedDirectives match {
399384
case Seq() =>
400385
Right(StrictDirectivesProcessingOutput(
401386
updatedRequirements.global,
402387
updatedOptions.global,
403388
updatedRequirements.scoped,
404-
updatedContentOpt,
389+
strippedContent = None,
405390
directivesPositions
406391
))
407392
case Seq(h, t*) =>
@@ -426,9 +411,6 @@ case object ScalaPreprocessor extends Preprocessor {
426411
)
427412
}
428413

429-
val changeToSpecialCommentMsg =
430-
"Using directive using plain comments are deprecated. Please use a special comment syntax: '//> ...' or '/*> ... */'"
431-
432414
private def parseDependency(str: String, pos: Position): Either[BuildException, AnyDependency] =
433415
DependencyParser.parse(str) match {
434416
case Left(msg) => Left(new DependencyFormatError(str, msg, positionOpt = Some(pos)))

modules/build/src/test/scala/scala/build/tests/DirectiveParsingTest.scala

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ class DirectiveParsingTest extends munit.FunSuite {
6161
code,
6262
Right(path),
6363
persistentLogger,
64-
UsingDirectiveKind.values(),
6564
ScopePath.fromPath(path),
6665
maybeRecoverOnError = e => Some(e)
6766
)
@@ -111,20 +110,18 @@ class DirectiveParsingTest extends munit.FunSuite {
111110
}
112111

113112
test("Test warnings about mixing syntax") {
114-
testDiagnostics(directive, specialCommentDirective)(Warn("ignored", 1, 0))
115-
testDiagnostics(directive, commentDirective)(Warn("ignored", 1, 0))
113+
testDiagnostics(directive, specialCommentDirective)(Warn("ignored", 0, 0))
114+
testDiagnostics(directive, commentDirective)(Warn("ignored", 0, 0))
116115
testDiagnostics(specialCommentDirective, commentDirective)(Warn("ignored", 1, 0))
117116
testDiagnostics(commentDirective, specialCommentDirective)(Warn("deprecated", 0, 0))
118117
}
119118

120-
test("Plain comment only result in no ignored warning") {
121-
testDiagnostics(commentDirective)(NoWarn("ignored"))
119+
test("Plain comment result in ignored warning") {
120+
testDiagnostics(commentDirective)(Warn("ignored", 0, 0))
122121
}
123122

124123
test("@using is deprecated") {
125124
def addAt(s: String) = s.replace("using ", "@using ")
126-
testDiagnostics(addAt(commentDirective))(Warn("syntax", 0, 3), Warn("keyword", 0, 3))
127-
testDiagnostics(addAt(directive))(Warn("syntax", 0, 0), Warn("keyword", 0, 0))
128125
testDiagnostics(addAt(specialCommentDirective))(Warn("syntax", 0, 4), Warn("keyword", 0, 4))
129126
}
130127

modules/build/src/test/scala/scala/build/tests/SourcesTests.scala

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -245,27 +245,6 @@ class SourcesTests extends munit.FunSuite {
245245
}
246246
}
247247

248-
test("should fail dependencies in .java with using keyword") {
249-
val testInputs = TestInputs(
250-
os.rel / "Something.java" ->
251-
"""using dep "org3:::name3:3.3"
252-
|
253-
|public class Something {
254-
| public Int a = 1;
255-
|}
256-
|""".stripMargin
257-
)
258-
testInputs.withInputs { (_, inputs) =>
259-
val crossSources = CrossSources.forInputs(
260-
inputs,
261-
preprocessors,
262-
TestLogger(),
263-
SuppressWarningOptions()
264-
)
265-
expect(crossSources.isLeft)
266-
}
267-
}
268-
269248
test("should fail for ammonite imports in .sc - $ivy") {
270249
val testInputs = TestInputs(
271250
os.rel / "something.sc" ->

website/docs/guides/using-directives.md

Lines changed: 15 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,13 @@ sidebar_position: 5
99

1010
The `using` directives mechanism lets you define configuration information within `.scala` source code files, eliminating the need for build tools to define a dedicated configuration syntax.
1111

12-
`using` directives are basically key-value pairs that let you provide multiple values to a single key. For instance, this command:
12+
`using` directives are basically key-value pairs that let you provide multiple values to a single key. These directives need to be put in comments with a special syntax. For instance, this command:
1313

1414
```scala
15-
using foo "bar", "baz"
15+
//> using foo "bar", "baz"
1616
```
1717

18-
will be interpreted as assigning `bar` and `baz` to the key `foo`.
19-
20-
As shown, `using` directives can be defined using the special keyword `using`. However, this may break existing tools outside of Scala CLI. Therefore, `using` directives can be put in comments with a special syntax:
21-
22-
```scala
23-
//> using scala "2"
24-
25-
/*> using options "-Xfatal-warnings" */
26-
```
27-
28-
:::info
29-
For now we recommend using the special comment (`//> using scala "3.0.2"`), and we will use that syntax in this guide.
30-
31-
Until `using` directives becomes a part of the Scala specification, this is the only way that guarantees that your code will work well with IDEs, code formatters, and other tools.
32-
:::
33-
34-
Within one file, only one flavor of using directives can be used. The keyword-based syntax (`using scala "3"`) has precedence over special comments (`//> using scala "3"`). The deprecated, plain comments (`// using scala "3"`) have lowest priority.
35-
36-
For now `using` and `@using` can be mixed within a given syntax however we strongly suggest not to use deprecated `@using`.
37-
38-
Scala CLI reports warnings for each using directive that does not contribute to the build.
18+
Scala CLI reports warnings for each using directive that does not contribute to the build, which includes all removed alternatives to special comment using directives.
3919

4020
With following snippet:
4121

@@ -45,19 +25,20 @@ using scala "3.1"
4525
//> using scala "2.12.11"
4626
```
4727

48-
Scala `3.1` will be used and following warnings would be reported:
28+
Scala `2.12.11` will be used and following warnings would be reported:
4929

5030
```
51-
[warn] ./.pg/a.scala:2:1: This using directive is ignored. File contains directives outside comments and those has higher precedence.
52-
[warn] // using scala "2.13.8"
31+
[warn] ./.pg/a.scala:1:1: This using directive is ignored. Only using directives starting with //> are supported.
32+
[warn] using scala "3.1"
5333
[warn] ^^^
54-
[warn] ./.pg/a.scala:3:1: This using directive is ignored. File contains directives outside comments and those has higher precedence.
55-
[warn] //> using scala "2.12.11"
34+
[warn] ./.pg/a.scala:2:1: Using directive using plain comments are deprecated. Please use a special comment syntax: '//> ...'.
35+
[warn] // using scala "2.13.8"
5636
[warn] ^^^^
5737
```
38+
5839
## Deprecated syntax
5940

60-
As a part of `0.0.x` series we experimented with different syntaxes for using directives. Based on feedback and discussions with the Scala compiler team, we decided to deprecate `@using` (using annotations) and `// using` (using within plain comment). Those syntaxes will keep working in the `0.1.x` series and will result in an error starting from `0.2.x`.
41+
As a part of `0.0.x` series we experimented with different syntaxes for using directives. Based on feedback and discussions with the Scala compiler team, we decided to remove `@using` (using annotations), `// using` (using within plain comment) and `using` code directives. Those syntaxes will keep working in the `0.1.x` series and will result in an error starting from `1.0.x`.
6142

6243
Scala CLI produces warnings if any of the syntaxes above is used:
6344

@@ -91,17 +72,6 @@ This means that a library or compiler option defined in one file applies to the
9172
The only exceptions are `using target` directives, which only apply to the given file.
9273
`using target` is a marker to assign a given file to a given target (e.g., test or main sources).
9374

94-
`using` directives also support indentation and braces syntax similar to the syntax of Scala:
95-
```scala
96-
//> using:
97-
//> scala "2.13"
98-
//> options "-Xasync"
99-
//> target {
100-
//> scope "test"
101-
//> platform "jvm"
102-
//> }
103-
```
104-
10575
**We believe that syntax similar to `using` directives should become a part of Scala in the future.**
10676

10777
## `using` directives in the Scala CLI
@@ -121,24 +91,24 @@ There are several reasons that we believe `using` directives are a good solution
12191

12292
- One of the main Scala CLI use cases is prototyping, and the ability to ship one or more source code files with a complete configuration is a game-changer for this use case.
12393
- Defining dependencies and other settings is common in Ammonite scripts as well.
124-
- From a teaching perspective, the ability to provide pre-configured pieces of code that fit into one slide is also benefical.
125-
- Having configuration close to the code is benefical, since often — especially in small programs — the given depencencies are only used within one source file.
94+
- From a teaching perspective, the ability to provide pre-configured pieces of code that fit into one slide is also beneficial.
95+
- Having configuration close to the code is beneficial, since often — especially in small programs — the given dependencies are only used within one source file.
12696

12797
We acknowledge that configuration distributed across many source files may be hard to maintain in the long term. Therefore, in the near feature we will introduce a set of lints to ensure that above a given project size or complexity, all configuration details will be centralized.
12898

12999
How can configuration that’s contained in source files be centralized?
130100
`using` directives can be placed in any `.scala` file, so it’s possible to create a `.scala` file that contains only configuration information.
131-
Therefore, when your project needs to centralize its configuration, we recommend creating a `conf.scala` file, and placing the configuration there.
101+
Therefore, when your project needs to centralize its configuration, we recommend creating a `project.scala` file, and placing the configuration there.
132102
We plan to add ways to Scala CLI to migrate these settings into a centralized location with one command or click.
133103

134104
We are aware that `using` directives may be a controversial topic, so we’ve created a [dedicated space for discussing `using` directives](https://github.com/VirtusLab/scala-cli/discussions/categories/using-directives-and-cmd-configuration-options).
135105

136106

137107
## How to comment out using directives?
138108

139-
Using directives are part of the code so similarly, developers should be able to comment them out. Until 0.2.x when plain comment syntax will be removed commenting out using directives requires special care.
109+
Using directives are part of the code so similarly, developers should be able to comment them out.
140110

141-
Paradoxically, commenting out comment-based directives does not cause any problems. Below, some examples how to do it:
111+
Commenting out comment-based directives does not cause any problems. Below, some examples how to do it:
142112

143113
```scala compile
144114
// //> using dep "no::lib:123"
@@ -148,29 +118,3 @@ Paradoxically, commenting out comment-based directives does not cause any proble
148118
// // using dep "no::lib:123"
149119
```
150120

151-
Until plain using directives in plain comments are supported, commenting keyword base syntax require some attention. Let' assume that we have a following code:
152-
153-
```scala fail
154-
using scala "3.1.1"
155-
using dep "no::lib:123"
156-
```
157-
158-
and we want to comment out broken using directive: `lib "no::lib:123"` when we simply comment it out we will actually turn it into a using directive that is using a plain comment syntax!
159-
160-
```scala compile
161-
using scala "3.1.1"
162-
// using dep "no::lib:123"
163-
```
164-
165-
In cases where there are other uncommented directives, scala-cli will ignore that directives, producing a warning. In cases that this is the only directive in the file, the commented directive will be still used to configure build.
166-
167-
In such cases we suggest to use triple `/` for single line comments, or use `//` withing multiline comments:
168-
169-
```scala compile
170-
/// using dep "in::single-line-comments:123"
171-
/*
172-
// using dep "in::multiline-line-comments:123"
173-
*/
174-
```
175-
176-
Generally, our recommendation is to not use keyword based directives until scala-cli will stop supporting plain comments-based directives.

0 commit comments

Comments
 (0)