summary refs log tree commit diff stats
path: root/compiler/layouter.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/layouter.nim')
-rw-r--r--compiler/layouter.nim56
1 files changed, 43 insertions, 13 deletions
diff --git a/compiler/layouter.nim b/compiler/layouter.nim
index cc6ec48b7..8605ade45 100644
--- a/compiler/layouter.nim
+++ b/compiler/layouter.nim
@@ -28,10 +28,10 @@ type
     config: ConfigRef
     fid: FileIndex
     lastTok: TTokType
-    inquote: bool
+    inquote, lastTokWasTerse: bool
     semicolons: SemicolonKind
-    col, lastLineNumber, lineSpan, indentLevel, indWidth: int
-    nested: int
+    col, lastLineNumber, lineSpan, indentLevel, indWidth*: int
+    keepIndents*: int
     doIndentMore*: int
     content: string
     indentStack: seq[int]
@@ -41,9 +41,10 @@ type
 proc openEmitter*(em: var Emitter, cache: IdentCache;
                   config: ConfigRef, fileIdx: FileIndex) =
   let fullPath = Absolutefile config.toFullPath(fileIdx)
-  em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead),
-                               cache, config)
-  if em.indWidth == 0: em.indWidth = 2
+  if em.indWidth == 0:
+    em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead),
+                                cache, config)
+    if em.indWidth == 0: em.indWidth = 2
   em.config = config
   em.fid = fileIdx
   em.lastTok = tkInvalid
@@ -52,11 +53,16 @@ proc openEmitter*(em: var Emitter, cache: IdentCache;
   em.content = newStringOfCap(16_000)
   em.indentStack = newSeqOfCap[int](30)
   em.indentStack.add 0
+  em.lastLineNumber = 1
 
 proc closeEmitter*(em: var Emitter) =
+  if fileExists(em.config.outFile) and readFile(em.config.outFile.string) == em.content:
+    discard "do nothing, see #9499"
+    return
   var f = llStreamOpen(em.config.outFile, fmWrite)
   if f == nil:
     rawMessage(em.config, errGenerated, "cannot open file: " & em.config.outFile.string)
+    return
   f.llStreamWrite em.content
   llStreamClose(f)
 
@@ -106,15 +112,16 @@ proc softLinebreak(em: var Emitter, lit: string) =
       for i in 1..em.indentLevel+moreIndent(em): wr(" ")
     else:
       # search backwards for a good split position:
-      for a in em.altSplitPos:
+      for a in mitems(em.altSplitPos):
         if a > em.fixedUntil:
           var spaces = 0
           while a+spaces < em.content.len and em.content[a+spaces] == ' ':
             inc spaces
           if spaces > 0: delete(em.content, a, a+spaces-1)
-          let ws = "\L" & repeat(' ',em.indentLevel+moreIndent(em))
           em.col = em.content.len - a
+          let ws = "\L" & repeat(' ', em.indentLevel+moreIndent(em))
           em.content.insert(ws, a)
+          a = -1
           break
 
 proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
@@ -134,6 +141,22 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
         for i in 1 .. LineCommentColumn - em.col: wr(" ")
     wr lit
 
+  if tok.tokType == tkComment and tok.literal.startsWith("#!nimpretty"):
+    case tok.literal
+    of "#!nimpretty off":
+      inc em.keepIndents
+      wr("\L")
+      em.lastLineNumber = tok.line + 1
+    of "#!nimpretty on":
+      dec em.keepIndents
+      em.lastLineNumber = tok.line
+    wr("\L")
+    #for i in 1 .. tok.indent: wr " "
+    wr tok.literal
+    em.col = 0
+    em.lineSpan = 0
+    return
+
   var preventComment = false
   if tok.tokType == tkComment and tok.line == em.lastLineNumber and tok.indent >= 0:
     # we have an inline comment so handle it before the indentation token:
@@ -142,7 +165,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
     em.fixedUntil = em.content.high
 
   elif tok.indent >= 0:
-    if em.lastTok in (splitters + oprSet):
+    if em.lastTok in (splitters + oprSet) or em.keepIndents > 0:
       em.indentLevel = tok.indent
     else:
       if tok.indent > em.indentStack[^1]:
@@ -171,12 +194,13 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
       wr(" ")
     em.fixedUntil = em.content.high
 
+  var lastTokWasTerse = false
   case tok.tokType
   of tokKeywordLow..tokKeywordHigh:
     if endsInAlpha(em):
       wr(" ")
     elif not em.inquote and not endsInWhite(em) and
-        em.lastTok notin openPars:
+        em.lastTok notin openPars and not em.lastTokWasTerse:
       #and tok.tokType in oprSet
       wr(" ")
 
@@ -212,14 +236,19 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
      tkBracketDotRi,
      tkCurlyDotRi,
      tkParDotRi,
-     tkColonColon, tkDot:
+     tkColonColon:
+    wr(TokTypeToStr[tok.tokType])
+  of tkDot:
+    lastTokWasTerse = true
     wr(TokTypeToStr[tok.tokType])
   of tkEquals:
     if not em.inquote and not em.endsInWhite: wr(" ")
     wr(TokTypeToStr[tok.tokType])
     if not em.inquote: wr(" ")
   of tkOpr, tkDotDot:
-    if tok.strongSpaceA == 0 and tok.strongSpaceB == 0:
+    if (tok.strongSpaceA == 0 and tok.strongSpaceB == 0) or em.inquote:
+      # bug #9504: remember to not spacify a keyword:
+      lastTokWasTerse = true
       # if not surrounded by whitespace, don't produce any whitespace either:
       wr(tok.ident.s)
     else:
@@ -229,8 +258,8 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
         tok.strongSpaceB == 0 and tok.strongSpaceA > 0
 
       if not isUnary(tok):
-        wr(" ")
         rememberSplit(splitBinary)
+        wr(" ")
   of tkAccent:
     if not em.inquote and endsInAlpha(em): wr(" ")
     wr(TokTypeToStr[tok.tokType])
@@ -253,6 +282,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
     wr lit
 
   em.lastTok = tok.tokType
+  em.lastTokWasTerse = lastTokWasTerse
   em.lastLineNumber = tok.line + em.lineSpan
   em.lineSpan = 0