Repository: sharkdp/bat (language: rust)

Issue:
Newline can be added even if --style=plain
In #975 @sharkdp said this:

> The fact that bat -p prints a trailing newline (even if there is no newline at the end of the file) should be considered a bug, I believe (but we should check older tickets, if there was a reason for this behavior).

And I completely agree. The reason the artificial newline was added in the first place was to fix #299, but there should be no risk of regressions since --style=plain excludes any kind of decorations that bug was about.

Note that a pager such as `less` will add an artificial newline too, so one either has to disable paging or use a "pager" that does not add a newline to get the benefit of fixing this bug.

**Step-by-step:**
1.  echo -n nonewline > nonewline.txt
2. bat --style=plain --paging=never nonewline.txt
3. bat --style=plain --pager=cat nonewline.txt

**Expected result:**
After 2. and 3. the line shall not contain a newline. I personally use `zsh` to check this since by default `zsh` will print e.g. `%` as the last char if there is a missing newline.

**Actual result:**
A newline is printed with `bat 0.17.1`.

(I will soon open a PR with a proposed fix)

Newline can be added even if --style=plain
In #975 @sharkdp said this:

> The fact that bat -p prints a trailing newline (even if there is no newline at the end of the file) should be considered a bug, I believe (but we should check older tickets, if there was a reason for this behavior).

And I completely agree. The reason the artificial newline was added in the first place was to fix #299, but there should be no risk of regressions since --style=plain excludes any kind of decorations that bug was about.

Note that a pager such as `less` will add an artificial newline too, so one either has to disable paging or use a "pager" that does not add a newline to get the benefit of fixing this bug.

**Step-by-step:**
1.  echo -n nonewline > nonewline.txt
2. bat --style=plain --paging=never nonewline.txt
3. bat --style=plain --pager=cat nonewline.txt

**Expected result:**
After 2. and 3. the line shall not contain a newline. I personally use `zsh` to check this since by default `zsh` will print e.g. `%` as the last char if there is a missing newline.

**Actual result:**
A newline is printed with `bat 0.17.1`.

(I will soon open a PR with a proposed fix)



Discussion / hints:
Thank you for taking the time to write this down in detail!
Thank you for taking the time to write this down in detail!

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a245131c64..dc65521678 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,8 @@
 
 ## Bugfixes
 
-- only print themes hint in interactive mode (`bat --list-themes`), see #1439 (@rsteube)
+- If the last line doesn't end with a newline character, don't add it if `--style=plain`, see #1438 (@Enselic)
+- Only print themes hint in interactive mode (`bat --list-themes`), see #1439 (@rsteube)
 - Make ./tests/syntax-tests/regression_test.sh work on recent versions of macOS, see #1443 (@Enselic)
 
 ## Other
diff --git a/src/preprocessor.rs b/src/preprocessor.rs
index eb87889027..7001ec88c7 100644
--- a/src/preprocessor.rs
+++ b/src/preprocessor.rs
@@ -72,7 +72,7 @@ pub fn replace_nonprintable(input: &[u8], tab_width: usize) -> String {
                     }
                 }
                 // line feed
-                '\x0A' => output.push('␊'),
+                '\x0A' => output.push_str("␊\x0A"),
                 // carriage return
                 '\x0D' => output.push('␍'),
                 // null
diff --git a/src/printer.rs b/src/printer.rs
index ba74872a5c..d588083e6e 100644
--- a/src/printer.rs
+++ b/src/printer.rs
@@ -91,9 +91,6 @@ impl<'a> Printer for SimplePrinter<'a> {
             if self.config.show_nonprintable {
                 let line = replace_nonprintable(line_buffer, self.config.tab_width);
                 write!(handle, "{}", line)?;
-                if line_buffer.last() == Some(&b'\n') {
-                    writeln!(handle)?;
-                }
             } else {
                 handle.write_all(line_buffer)?
             };
@@ -463,7 +460,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
                 }
             }
 
-            if line.bytes().next_back() != Some(b'\n') {
+            if !self.config.style_components.plain() && line.bytes().next_back() != Some(b'\n') {
                 writeln!(handle)?;
             }
         } else {


Test patch:
diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs
index ac11efb4b8..d02170219b 100644
--- a/tests/integration_tests.rs
+++ b/tests/integration_tests.rs
@@ -813,3 +813,17 @@ fn show_all_mode() {
         .stdout("hello·world␊\n├──┤␍␀␇␈␛")
         .stderr("");
 }
+
+#[test]
+fn plain_mode_does_not_add_nonexisting_newline() {
+    bat()
+        .arg("--paging=never")
+        .arg("--color=never")
+        .arg("--decorations=always")
+        .arg("--style=plain")
+        .arg("single-line.txt")
+        .assert()
+        .success()
+        .stdout("Single Line");
+}
+
diff --git a/tests/syntax-tests/highlighted/Plaintext/plaintext.txt b/tests/syntax-tests/highlighted/Plaintext/plaintext.txt
index 807728e157..1f27a79f48 100644
--- a/tests/syntax-tests/highlighted/Plaintext/plaintext.txt
+++ b/tests/syntax-tests/highlighted/Plaintext/plaintext.txt
@@ -175,4 +175,4 @@
 [38;2;117;113;94m\u{ad}[0m[38;2;249;38;114m␊[0m
 [38;2;117;113;94m\u{ae}[0m[38;2;249;38;114m␊[0m
 [38;2;249;38;114m␊[0m
-[38;2;248;248;242mHere's[0m[38;2;102;217;239m·[0m[38;2;248;248;242ma[0m[38;2;102;217;239m·[0m[38;2;248;248;242mline[0m[38;2;102;217;239m·[0m[38;2;248;248;242mwith[0m[38;2;102;217;239m·[0m[38;2;248;248;242mmultiple[0m[38;2;102;217;239m·[0m[38;2;248;248;242mcharacters.[0m
+[38;2;248;248;242mHere's[0m[38;2;102;217;239m·[0m[38;2;248;248;242ma[0m[38;2;102;217;239m·[0m[38;2;248;248;242mline[0m[38;2;102;217;239m·[0m[38;2;248;248;242mwith[0m[38;2;102;217;239m·[0m[38;2;248;248;242mmultiple[0m[38;2;102;217;239m·[0m[38;2;248;248;242mcharacters.[0m[38;2;249;38;114m␊[0m
diff --git a/tests/syntax-tests/source/ActionScript/test.as b/tests/syntax-tests/source/ActionScript/test.as
index 1f7a1936aa..f1828bbcd4 100644
--- a/tests/syntax-tests/source/ActionScript/test.as
+++ b/tests/syntax-tests/source/ActionScript/test.as
@@ -72,4 +72,4 @@ package TestSyntax {
             var sndChannel:SoundChannel = mySound.play();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/syntax-tests/source/Batch/build.bat b/tests/syntax-tests/source/Batch/build.bat
index 56a262e255..acf9f7cdf8 100644
--- a/tests/syntax-tests/source/Batch/build.bat
+++ b/tests/syntax-tests/source/Batch/build.bat
@@ -56,4 +56,4 @@ set LDLIBS= ^
     @set "LINK_FILES=%LINK_FILES% %%~f"
 )
 
-lld-link.exe %LINK_FILES% -out:"%OUTPUT%" %LDFLAGS% %LDLIBS%
\ No newline at end of file
+lld-link.exe %LINK_FILES% -out:"%OUTPUT%" %LDFLAGS% %LDLIBS%
diff --git a/tests/syntax-tests/source/Clojure/test.clj b/tests/syntax-tests/source/Clojure/test.clj
index ea24e822a7..b4010da10d 100644
--- a/tests/syntax-tests/source/Clojure/test.clj
+++ b/tests/syntax-tests/source/Clojure/test.clj
@@ -55,4 +55,4 @@
     (println (factorial 5))
     (log)
     (log "Message"))
-  
\ No newline at end of file
+  
diff --git a/tests/syntax-tests/source/Dockerfile/Dockerfile b/tests/syntax-tests/source/Dockerfile/Dockerfile
index 54a3b2c888..b38bce26d6 100644
--- a/tests/syntax-tests/source/Dockerfile/Dockerfile
+++ b/tests/syntax-tests/source/Dockerfile/Dockerfile
@@ -16,4 +16,4 @@ EXPOSE 80/tcp
 
 VOLUME [/var/lib/mysql/data]
 
-ENTRYPOINT ["/usr/bin/entrypoint.sh"]
\ No newline at end of file
+ENTRYPOINT ["/usr/bin/entrypoint.sh"]
diff --git a/tests/syntax-tests/source/Git Attributes/example.gitattributes b/tests/syntax-tests/source/Git Attributes/example.gitattributes
index 9b8e58b882..8b3502b74b 100644
--- a/tests/syntax-tests/source/Git Attributes/example.gitattributes
+++ b/tests/syntax-tests/source/Git Attributes/example.gitattributes
@@ -13,4 +13,4 @@
 *.patch    -text
 
 .gitattributes linguist-language=gitattributes
-.gitkeep       export-ignore
\ No newline at end of file
+.gitkeep       export-ignore
diff --git a/tests/syntax-tests/source/Git Config/text.gitconfig b/tests/syntax-tests/source/Git Config/text.gitconfig
index 45de0fe53c..47224f0ba8 100644
--- a/tests/syntax-tests/source/Git Config/text.gitconfig
+++ b/tests/syntax-tests/source/Git Config/text.gitconfig
@@ -104,4 +104,4 @@
 [user]
 	email = f.nord@example.com
 	name = Frank Nord
-	signingkey = AAAAAAAAAAAAAAAA
\ No newline at end of file
+	signingkey = AAAAAAAAAAAAAAAA
diff --git a/tests/syntax-tests/source/Hosts/hosts b/tests/syntax-tests/source/Hosts/hosts
index d7d4307d4a..e9d24c2dc2 100644
--- a/tests/syntax-tests/source/Hosts/hosts
+++ b/tests/syntax-tests/source/Hosts/hosts
@@ -5,4 +5,4 @@
 192.160.0.200        try.sample.test try     #another comment
 216.58.223.238       google.com
 
-::1 localhost.try ip6-localhost
\ No newline at end of file
+::1 localhost.try ip6-localhost
diff --git a/tests/syntax-tests/source/Makefile/Makefile b/tests/syntax-tests/source/Makefile/Makefile
index 7acc5b2da0..8737973302 100644
--- a/tests/syntax-tests/source/Makefile/Makefile
+++ b/tests/syntax-tests/source/Makefile/Makefile
@@ -382,4 +382,4 @@ install: all
 	@ln -sf $(REDIS_SERVER_NAME) $(INSTALL_BIN)/$(REDIS_SENTINEL_NAME)
 
 uninstall:
-	rm -f $(INSTALL_BIN)/{$(REDIS_SERVER_NAME),$(REDIS_BENCHMARK_NAME),$(REDIS_CLI_NAME),$(REDIS_CHECK_RDB_NAME),$(REDIS_CHECK_AOF_NAME),$(REDIS_SENTINEL_NAME)}
\ No newline at end of file
+	rm -f $(INSTALL_BIN)/{$(REDIS_SERVER_NAME),$(REDIS_BENCHMARK_NAME),$(REDIS_CLI_NAME),$(REDIS_CHECK_RDB_NAME),$(REDIS_CHECK_AOF_NAME),$(REDIS_SENTINEL_NAME)}
diff --git a/tests/syntax-tests/source/PHP/test.php b/tests/syntax-tests/source/PHP/test.php
index 264135976e..1f0a581fcd 100644
--- a/tests/syntax-tests/source/PHP/test.php
+++ b/tests/syntax-tests/source/PHP/test.php
@@ -108,4 +108,4 @@ function setName($name) {
 
 $ending = 2 > 3 ? "yep" : "nah";
 
-?>
\ No newline at end of file
+?>
diff --git a/tests/syntax-tests/source/Plaintext/plaintext.txt b/tests/syntax-tests/source/Plaintext/plaintext.txt
index 42da1207d3..112ef7e923 100644
Binary files a/tests/syntax-tests/source/Plaintext/plaintext.txt and b/tests/syntax-tests/source/Plaintext/plaintext.txt differ
diff --git a/tests/syntax-tests/source/PowerShell/test.ps1 b/tests/syntax-tests/source/PowerShell/test.ps1
index 434414df40..315149a8dd 100755
Binary files a/tests/syntax-tests/source/PowerShell/test.ps1 and b/tests/syntax-tests/source/PowerShell/test.ps1 differ
diff --git a/tests/syntax-tests/source/RequirementsTXT/requirements.txt b/tests/syntax-tests/source/RequirementsTXT/requirements.txt
index 83a41dc8b2..83d71e0ea3 100644
--- a/tests/syntax-tests/source/RequirementsTXT/requirements.txt
+++ b/tests/syntax-tests/source/RequirementsTXT/requirements.txt
@@ -5,4 +5,4 @@ pywheels>=12.4 #a whitespace followed by comments
 Nuitka<0.6.8.4
 wxPython>=1.0, <=2.1
 
-#this is another comment
\ No newline at end of file
+#this is another comment
diff --git a/tests/syntax-tests/source/YAML/example.yaml b/tests/syntax-tests/source/YAML/example.yaml
index 1b2157052e..d7b4c912d4 100644
--- a/tests/syntax-tests/source/YAML/example.yaml
+++ b/tests/syntax-tests/source/YAML/example.yaml
@@ -31,4 +31,4 @@ emails:
       - bob@example.com
       - bill@example.com
     supervisors:
-      - george@example.com
\ No newline at end of file
+      - george@example.com
diff --git a/tests/syntax-tests/source/reStructuredText/reference.rst b/tests/syntax-tests/source/reStructuredText/reference.rst
index e07f54c46a..5c42e54089 100644
--- a/tests/syntax-tests/source/reStructuredText/reference.rst
+++ b/tests/syntax-tests/source/reStructuredText/reference.rst
@@ -317,4 +317,4 @@ blank lines before and after.)
 ..
 
         So this block is not "lost",
-        despite its indentation.
\ No newline at end of file
+        despite its indentation.