diff --git a/CHANGELOG.md b/CHANGELOG.md
index 09e9b569..df7a4c55 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,8 @@ Jupytext ChangeLog
- Some dependencies of the JupyterLab extensions were updated ([#1243](https://github.com/mwouts/jupytext/issues/1243), [#1245](https://github.com/mwouts/jupytext/issues/1245))
**Added**
-- Added support for Lua notebooks ([#1252](https://github.com/mwouts/jupytext/pull/1252)) - thanks to [erentar](https://github.com/erentar) for this contribution
+- Lua notebooks are now supported ([#1252](https://github.com/mwouts/jupytext/pull/1252)) - thanks to [erentar](https://github.com/erentar) for this contribution
+- Go notebooks are supported too ([#1244](https://github.com/mwouts/jupytext/issues/1244))! Many thanks to [Jan Pfeifer](https://github.com/janpfeifer), author of [GoNB](https://github.com/janpfeifer/gonb), and to [HaveF](https://github.com/HaveF) for their help on this topic.
- Empty prefixes are now allowed in Jupytext format when specified as a dictionary ([#1144](https://github.com/mwouts/jupytext/issues/1144))
diff --git a/docs/languages.md b/docs/languages.md
index 055d0905..7970d82c 100644
--- a/docs/languages.md
+++ b/docs/languages.md
@@ -9,6 +9,7 @@ Jupytext works with notebooks in any of the following languages:
- Coconut
- F#
- Gnuplot
+- Go
- Groovy
- Haskell
- IDL
diff --git a/src/jupytext/cell_reader.py b/src/jupytext/cell_reader.py
index ba09b83b..52f4f299 100644
--- a/src/jupytext/cell_reader.py
+++ b/src/jupytext/cell_reader.py
@@ -555,6 +555,11 @@ def uncomment_code_and_magics(self, lines):
else:
lines = uncomment(lines)
+ if self.default_language == "go" and self.language is None:
+ lines = [
+ re.sub(r"^((//\s*)*)(//\s*gonb:%%)", r"\1%%", line) for line in lines
+ ]
+
if self.cell_type == "code":
return unescape_code_start(
lines, self.ext, self.language or self.default_language
diff --git a/src/jupytext/cell_to_text.py b/src/jupytext/cell_to_text.py
index 24fe6ea5..bf40ab3a 100644
--- a/src/jupytext/cell_to_text.py
+++ b/src/jupytext/cell_to_text.py
@@ -135,6 +135,13 @@ def cell_to_text(self):
if self.cell_type != "code" and not self.metadata and self.use_triple_quotes():
self.metadata["cell_type"] = self.cell_type
+ # Go notebooks have '%%' or '%% -' magic commands that need to be escaped
+ if self.default_language == "go" and self.language == "go":
+ self.source = [
+ re.sub(r"^(//\s*)*(%%\s*$|%%\s+-.*$)", r"\1//gonb:\2", line)
+ for line in self.source
+ ]
+
if self.is_code():
return self.code_to_text()
@@ -487,6 +494,13 @@ def __init__(self, *args, **kwargs):
def cell_to_text(self):
"""Return the text representation for the cell"""
+ # Go notebooks have '%%' or '%% -' magic commands that need to be escaped
+ if self.default_language == "go" and self.language == "go":
+ self.source = [
+ re.sub(r"^(//\s*)*(%%\s*$|%%\s+-.*$)", r"\1//gonb:\2", line)
+ for line in self.source
+ ]
+
active = is_active(
self.ext, self.metadata, same_language(self.language, self.default_language)
)
diff --git a/src/jupytext/languages.py b/src/jupytext/languages.py
index 28133a45..446cd1a6 100644
--- a/src/jupytext/languages.py
+++ b/src/jupytext/languages.py
@@ -1,4 +1,5 @@
"""Determine notebook or cell language"""
+import re
# Jupyter magic commands that are also languages
_JUPYTER_LANGUAGES = [
@@ -92,6 +93,7 @@
},
".xsh": {"language": "xonsh", "comment": "#"},
".lua": {"language": "lua", "comment": "--"},
+ ".go": {"language": "go", "comment": "//"},
}
_COMMENT_CHARS = [
@@ -110,6 +112,7 @@
_JUPYTER_LANGUAGES_LOWER_AND_UPPER = _JUPYTER_LANGUAGES.union(
{str.upper(lang) for lang in _JUPYTER_LANGUAGES}
)
+_GO_DOUBLE_PERCENT_COMMAND = re.compile(r"^(%%\s*|%%\s+-.*)$")
def default_language_from_metadata_and_ext(metadata, ext, pop_main_language=False):
@@ -206,6 +209,8 @@ def cell_language(source, default_language, custom_cell_magics):
"""Return cell language and language options, if any"""
if source:
line = source[0]
+ if default_language == "go" and _GO_DOUBLE_PERCENT_COMMAND.match(line):
+ return None, None
if default_language == "csharp":
if line.startswith("#!"):
lang = line[2:].strip()
diff --git a/src/jupytext/magics.py b/src/jupytext/magics.py
index babda739..72f77842 100644
--- a/src/jupytext/magics.py
+++ b/src/jupytext/magics.py
@@ -41,6 +41,10 @@ def get_comment(ext):
_MAGIC_FORCE_ESC_RE["csharp"] = re.compile(r"^(// |//)*#//\s*escape")
_MAGIC_FORCE_ESC_RE["csharp"] = re.compile(r"^(// |//)*#//\s*noescape")
+# Go magics might start with % or ! or !*
+# (in addition, Go NB might use %% or %% -, see "_GO_DOUBLE_PERCENT_COMMAND")
+_MAGIC_RE["go"] = re.compile(r"^(// |//)*(!|!\*|%|%%|%%%)[a-zA-Z]")
+
# Commands starting with a question or exclamation mark have to be escaped
_PYTHON_HELP_OR_BASH_CMD = re.compile(r"^\s*(# |#)*\s*(\?|!)\s*[A-Za-z\.\~\$\\\/\{\}]")
diff --git a/tests/data/notebooks/inputs/ipynb_go/hello_world_gonb.ipynb b/tests/data/notebooks/inputs/ipynb_go/hello_world_gonb.ipynb
new file mode 100644
index 00000000..3799ab33
--- /dev/null
+++ b/tests/data/notebooks/inputs/ipynb_go/hello_world_gonb.ipynb
@@ -0,0 +1,149 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "8795db3a-af9a-4f03-a68d-019330861b54",
+ "metadata": {},
+ "source": [
+ "A notebook that use [GoNB](https://github.com/janpfeifer/gonb)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "50a2fb21-01b3-46d0-9951-f9a1301a85ca",
+ "metadata": {},
+ "source": [
+ "the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "75d8418d-a918-4cc8-b42e-384db01f21ae",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "func main() {\n",
+ " fmt.Printf(\"Hello World!\")\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3620f46f-efd5-4454-bc29-418297012ce9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%%\n",
+ "fmt.Printf(\"Hello World!\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7fed4a43",
+ "metadata": {},
+ "source": [
+ "%% --who=world can pass flags to main func"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "473e2d02",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import (\n",
+ " \"flag\"\n",
+ " \"fmt\"\n",
+ ")\n",
+ "\n",
+ "var flagWho = flag.String(\"who\", \"\", \"Your name!\")\n",
+ "\n",
+ "%% --who=world\n",
+ "fmt.Printf(\"Hello %s!\\n\", *flagWho)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b8e8b4ae",
+ "metadata": {},
+ "source": [
+ "%args also can pass flags"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "348efbe1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%args --who=Wally\n",
+ "\n",
+ "func main() {\n",
+ " flag.Parse()\n",
+ " fmt.Printf(\"Where is %s?\", *flagWho)\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "82f4bb1f-3311-4fca-8025-c54c0305dc64",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import \"github.com/janpfeifer/gonb/gonbui\"\n",
+ "\n",
+ "%%\n",
+ "gonbui.DisplayHtml(`I 🧡 GoNB!`)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1a5584ff-f346-45cf-95c1-a3e3b7146c6c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%%\n",
+ "gonbui.DisplayMarkdown(\"#### Objective\\n\\n1. Have fun coding **Go**;\\n1. Profit...\\n\"+\n",
+ " `$$f(x) = \\int_{-\\infty}^{\\infty} e^{-x^2} dx$$`)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "de996381-d92c-4ce6-a135-50cf39288aa1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "func init_a() {\n",
+ " fmt.Println(\"init_a\")\n",
+ "}\n",
+ "%%\n",
+ "fmt.Println(\"main\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Go (gonb)",
+ "language": "go",
+ "name": "gonb"
+ },
+ "language_info": {
+ "codemirror_mode": "",
+ "file_extension": ".go",
+ "mimetype": "",
+ "name": "go",
+ "nbconvert_exporter": "",
+ "pygments_lexer": "",
+ "version": "go1.21.6"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/tests/data/notebooks/outputs/ipynb_to_Rmd/hello_world_gonb.Rmd b/tests/data/notebooks/outputs/ipynb_to_Rmd/hello_world_gonb.Rmd
new file mode 100644
index 00000000..70e15060
--- /dev/null
+++ b/tests/data/notebooks/outputs/ipynb_to_Rmd/hello_world_gonb.Rmd
@@ -0,0 +1,69 @@
+---
+jupyter:
+ kernelspec:
+ display_name: Go (gonb)
+ language: go
+ name: gonb
+---
+
+A notebook that use [GoNB](https://github.com/janpfeifer/gonb)
+
+
+the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb)
+
+```{go}
+func main() {
+ fmt.Printf("Hello World!")
+}
+```
+
+```{go}
+%%
+fmt.Printf("Hello World!")
+```
+
+%% --who=world can pass flags to main func
+
+```{go}
+import (
+ "flag"
+ "fmt"
+)
+
+var flagWho = flag.String("who", "", "Your name!")
+
+%% --who=world
+fmt.Printf("Hello %s!\n", *flagWho)
+```
+
+%args also can pass flags
+
+```{go}
+// %args --who=Wally
+
+func main() {
+ flag.Parse()
+ fmt.Printf("Where is %s?", *flagWho)
+}
+```
+
+```{go}
+import "github.com/janpfeifer/gonb/gonbui"
+
+%%
+gonbui.DisplayHtml(`I 🧡 GoNB!`)
+```
+
+```{go}
+%%
+gonbui.DisplayMarkdown("#### Objective\n\n1. Have fun coding **Go**;\n1. Profit...\n"+
+ `$$f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx$$`)
+```
+
+```{go}
+func init_a() {
+ fmt.Println("init_a")
+}
+%%
+fmt.Println("main")
+```
diff --git a/tests/data/notebooks/outputs/ipynb_to_hydrogen/hello_world_gonb.go b/tests/data/notebooks/outputs/ipynb_to_hydrogen/hello_world_gonb.go
new file mode 100644
index 00000000..7479a8cd
--- /dev/null
+++ b/tests/data/notebooks/outputs/ipynb_to_hydrogen/hello_world_gonb.go
@@ -0,0 +1,66 @@
+// -*- coding: utf-8 -*-
+// ---
+// jupyter:
+// kernelspec:
+// display_name: Go (gonb)
+// language: go
+// name: gonb
+// ---
+
+// %% [markdown]
+// A notebook that use [GoNB](https://github.com/janpfeifer/gonb)
+
+// %% [markdown]
+// the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb)
+
+// %%
+func main() {
+ fmt.Printf("Hello World!")
+}
+
+// %%
+//gonb:%%
+fmt.Printf("Hello World!")
+
+// %% [markdown]
+// //gonb:%% --who=world can pass flags to main func
+
+// %%
+import (
+ "flag"
+ "fmt"
+)
+
+var flagWho = flag.String("who", "", "Your name!")
+
+//gonb:%% --who=world
+fmt.Printf("Hello %s!\n", *flagWho)
+
+// %% [markdown]
+// %args also can pass flags
+
+// %%
+%args --who=Wally
+
+func main() {
+ flag.Parse()
+ fmt.Printf("Where is %s?", *flagWho)
+}
+
+// %%
+import "github.com/janpfeifer/gonb/gonbui"
+
+//gonb:%%
+gonbui.DisplayHtml(`I 🧡 GoNB!`)
+
+// %%
+//gonb:%%
+gonbui.DisplayMarkdown("#### Objective\n\n1. Have fun coding **Go**;\n1. Profit...\n"+
+ `$$f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx$$`)
+
+// %%
+func init_a() {
+ fmt.Println("init_a")
+}
+//gonb:%%
+fmt.Println("main")
diff --git a/tests/data/notebooks/outputs/ipynb_to_md/hello_world_gonb.md b/tests/data/notebooks/outputs/ipynb_to_md/hello_world_gonb.md
new file mode 100644
index 00000000..fa24d6b1
--- /dev/null
+++ b/tests/data/notebooks/outputs/ipynb_to_md/hello_world_gonb.md
@@ -0,0 +1,69 @@
+---
+jupyter:
+ kernelspec:
+ display_name: Go (gonb)
+ language: go
+ name: gonb
+---
+
+A notebook that use [GoNB](https://github.com/janpfeifer/gonb)
+
+
+the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb)
+
+```go
+func main() {
+ fmt.Printf("Hello World!")
+}
+```
+
+```go
+%%
+fmt.Printf("Hello World!")
+```
+
+%% --who=world can pass flags to main func
+
+```go
+import (
+ "flag"
+ "fmt"
+)
+
+var flagWho = flag.String("who", "", "Your name!")
+
+%% --who=world
+fmt.Printf("Hello %s!\n", *flagWho)
+```
+
+%args also can pass flags
+
+```go
+%args --who=Wally
+
+func main() {
+ flag.Parse()
+ fmt.Printf("Where is %s?", *flagWho)
+}
+```
+
+```go
+import "github.com/janpfeifer/gonb/gonbui"
+
+%%
+gonbui.DisplayHtml(`I 🧡 GoNB!`)
+```
+
+```go
+%%
+gonbui.DisplayMarkdown("#### Objective\n\n1. Have fun coding **Go**;\n1. Profit...\n"+
+ `$$f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx$$`)
+```
+
+```go
+func init_a() {
+ fmt.Println("init_a")
+}
+%%
+fmt.Println("main")
+```
diff --git a/tests/data/notebooks/outputs/ipynb_to_myst/hello_world_gonb.md b/tests/data/notebooks/outputs/ipynb_to_myst/hello_world_gonb.md
new file mode 100644
index 00000000..6ce0c8c1
--- /dev/null
+++ b/tests/data/notebooks/outputs/ipynb_to_myst/hello_world_gonb.md
@@ -0,0 +1,69 @@
+---
+kernelspec:
+ display_name: Go (gonb)
+ language: go
+ name: gonb
+---
+
+A notebook that use [GoNB](https://github.com/janpfeifer/gonb)
+
++++
+
+the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb)
+
+```{code-cell}
+func main() {
+ fmt.Printf("Hello World!")
+}
+```
+
+```{code-cell}
+%%
+fmt.Printf("Hello World!")
+```
+
+%% --who=world can pass flags to main func
+
+```{code-cell}
+import (
+ "flag"
+ "fmt"
+)
+
+var flagWho = flag.String("who", "", "Your name!")
+
+%% --who=world
+fmt.Printf("Hello %s!\n", *flagWho)
+```
+
+%args also can pass flags
+
+```{code-cell}
+%args --who=Wally
+
+func main() {
+ flag.Parse()
+ fmt.Printf("Where is %s?", *flagWho)
+}
+```
+
+```{code-cell}
+import "github.com/janpfeifer/gonb/gonbui"
+
+%%
+gonbui.DisplayHtml(`I 🧡 GoNB!`)
+```
+
+```{code-cell}
+%%
+gonbui.DisplayMarkdown("#### Objective\n\n1. Have fun coding **Go**;\n1. Profit...\n"+
+ `$$f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx$$`)
+```
+
+```{code-cell}
+func init_a() {
+ fmt.Println("init_a")
+}
+%%
+fmt.Println("main")
+```
diff --git a/tests/data/notebooks/outputs/ipynb_to_percent/hello_world_gonb.go b/tests/data/notebooks/outputs/ipynb_to_percent/hello_world_gonb.go
new file mode 100644
index 00000000..c9f8ddc3
--- /dev/null
+++ b/tests/data/notebooks/outputs/ipynb_to_percent/hello_world_gonb.go
@@ -0,0 +1,66 @@
+// -*- coding: utf-8 -*-
+// ---
+// jupyter:
+// kernelspec:
+// display_name: Go (gonb)
+// language: go
+// name: gonb
+// ---
+
+// %% [markdown]
+// A notebook that use [GoNB](https://github.com/janpfeifer/gonb)
+
+// %% [markdown]
+// the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb)
+
+// %%
+func main() {
+ fmt.Printf("Hello World!")
+}
+
+// %%
+//gonb:%%
+fmt.Printf("Hello World!")
+
+// %% [markdown]
+// //gonb:%% --who=world can pass flags to main func
+
+// %%
+import (
+ "flag"
+ "fmt"
+)
+
+var flagWho = flag.String("who", "", "Your name!")
+
+//gonb:%% --who=world
+fmt.Printf("Hello %s!\n", *flagWho)
+
+// %% [markdown]
+// %args also can pass flags
+
+// %%
+// %args --who=Wally
+
+func main() {
+ flag.Parse()
+ fmt.Printf("Where is %s?", *flagWho)
+}
+
+// %%
+import "github.com/janpfeifer/gonb/gonbui"
+
+//gonb:%%
+gonbui.DisplayHtml(`I 🧡 GoNB!`)
+
+// %%
+//gonb:%%
+gonbui.DisplayMarkdown("#### Objective\n\n1. Have fun coding **Go**;\n1. Profit...\n"+
+ `$$f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx$$`)
+
+// %%
+func init_a() {
+ fmt.Println("init_a")
+}
+//gonb:%%
+fmt.Println("main")
diff --git a/tests/data/notebooks/outputs/ipynb_to_script/hello_world_gonb.go b/tests/data/notebooks/outputs/ipynb_to_script/hello_world_gonb.go
new file mode 100644
index 00000000..ec544af8
--- /dev/null
+++ b/tests/data/notebooks/outputs/ipynb_to_script/hello_world_gonb.go
@@ -0,0 +1,60 @@
+// -*- coding: utf-8 -*-
+// ---
+// jupyter:
+// kernelspec:
+// display_name: Go (gonb)
+// language: go
+// name: gonb
+// ---
+
+// A notebook that use [GoNB](https://github.com/janpfeifer/gonb)
+
+// the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb)
+
+func main() {
+ fmt.Printf("Hello World!")
+}
+
+//gonb:%%
+fmt.Printf("Hello World!")
+
+// //gonb:%% --who=world can pass flags to main func
+
+// +
+import (
+ "flag"
+ "fmt"
+)
+
+var flagWho = flag.String("who", "", "Your name!")
+
+//gonb:%% --who=world
+fmt.Printf("Hello %s!\n", *flagWho)
+// -
+
+// // %args also can pass flags
+
+// +
+// %args --who=Wally
+
+func main() {
+ flag.Parse()
+ fmt.Printf("Where is %s?", *flagWho)
+}
+
+// +
+import "github.com/janpfeifer/gonb/gonbui"
+
+//gonb:%%
+gonbui.DisplayHtml(`I 🧡 GoNB!`)
+// -
+
+//gonb:%%
+gonbui.DisplayMarkdown("#### Objective\n\n1. Have fun coding **Go**;\n1. Profit...\n"+
+ `$$f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx$$`)
+
+func init_a() {
+ fmt.Println("init_a")
+}
+//gonb:%%
+fmt.Println("main")
diff --git a/tests/functional/simple_notebooks/test_read_simple_go.py b/tests/functional/simple_notebooks/test_read_simple_go.py
new file mode 100644
index 00000000..26cf2938
--- /dev/null
+++ b/tests/functional/simple_notebooks/test_read_simple_go.py
@@ -0,0 +1,156 @@
+import jupytext
+from jupytext.compare import compare
+
+
+def test_read_simple_file(
+ go="""// -*- coding: utf-8 -*-
+// ---
+// jupyter:
+// kernelspec:
+// display_name: Go (gonb)
+// language: go
+// name: gonb
+// ---
+
+// A notebook that use [GoNB](https://github.com/janpfeifer/gonb)
+
+// the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb)
+
+func main() {
+ fmt.Printf("Hello World!")
+}
+""",
+):
+ nb = jupytext.reads(go, "go:light")
+ assert len(nb.cells) == 3
+ assert nb.cells[0].cell_type == "markdown"
+ assert nb.cells[1].cell_type == "markdown"
+ assert nb.cells[2].cell_type == "code"
+
+
+def test_read_go_notebook_with_percent_percent_and_arguments(
+ go="""// %% [markdown]
+// # Square Function
+//
+// Defines a function $f(x) = x^2$
+
+// %%
+func Square(x float64) float64 {
+ return x*x
+}
+
+// %% [markdown]
+// # Examples
+//
+// ## Example A: $x = 3$
+
+// %%
+var x = flag.Float64("x", 0.0, "value of x to feed f(x)")
+
+//gonb:%% -x=3
+fmt.Printf("Square(%g)=%g\n", *x, Square(*x))
+
+// %% [markdown]
+// ## Example B: $x = 4$
+
+// %%
+//gonb:%% -x=4
+fmt.Printf("Square(%g)=%g\n", *x, Square(*x))
+""",
+):
+ nb = jupytext.reads(go, "go")
+ for cell in nb.cells:
+ assert "gonb" not in cell.source, cell.source
+
+ go2 = jupytext.writes(nb, "go")
+ compare(go2, go)
+
+
+def test_read_go_notebook_with_magic_main(
+ go="""// %%
+package square
+
+// %% [markdown]
+// # Defining a $x^2$ function
+// It returns x*x.
+
+// %%
+func Square(x float64) float64 {
+ return x * x
+}
+
+// %% [markdown]
+// # Examples
+//
+// ## Example A: $x = 3$
+
+// %%
+var x = flag.Float64("x", 0.0, "Value of x")
+
+func example() {
+ fmt.Printf("Square(%g)=%g\n", *x, Square(*x))
+}
+// %main example -x=3
+
+// %% [markdown]
+// ## Example B: $x = 4$
+
+// %%
+// %main example -x=4
+""",
+):
+ nb = jupytext.reads(go, "go")
+ for cell in nb.cells:
+ assert "gonb" not in cell.source, cell.source
+
+ go2 = jupytext.writes(nb, "go")
+ compare(go2, go)
+
+
+def test_commented_magic(
+ go="""// %%
+// This is a commented magic
+// //gonb:%%
+
+// %% [markdown]
+// This is a commented magic in a markdown cell
+// // //gonb:%%
+""",
+):
+ nb = jupytext.reads(go, "go")
+ assert len(nb.cells) == 2
+ assert nb.cells[0].cell_type == "code"
+ assert (
+ nb.cells[0].source
+ == """// This is a commented magic
+// %%"""
+ )
+ assert nb.cells[1].cell_type == "markdown"
+ assert (
+ nb.cells[1].source
+ == """This is a commented magic in a markdown cell
+// %%"""
+ )
+ go2 = jupytext.writes(nb, "go")
+ compare(go2, go)
+
+
+def test_magic_commands_are_commented(
+ go="""// %%
+// !*rm -f go.work && go work init && go work use . ${HOME}/Projects/gopjrt
+// %goworkfix
+// %env LD_LIBRARY_PATH=/usr/local/lib
+""",
+):
+ nb = jupytext.reads(go, "go:percent")
+ assert len(nb.cells) == 1
+ assert nb.cells[0].cell_type == "code"
+ assert (
+ nb.cells[0].source
+ == """!*rm -f go.work && go work init && go work use . ${HOME}/Projects/gopjrt
+%goworkfix
+%env LD_LIBRARY_PATH=/usr/local/lib"""
+ )
+
+ go2 = jupytext.writes(nb, "go")
+ compare(go2, go)
diff --git a/tests/functional/simple_notebooks/test_read_simple_percent.py b/tests/functional/simple_notebooks/test_read_simple_percent.py
index eea25a5c..1a5476f4 100644
--- a/tests/functional/simple_notebooks/test_read_simple_percent.py
+++ b/tests/functional/simple_notebooks/test_read_simple_percent.py
@@ -555,3 +555,54 @@ def test_cell_marker_has_same_indentation_as_code(
compare_notebooks(nb_actual, nb_expected)
text_actual = jupytext.writes(nb_actual, fmt="py:percent")
compare(text_actual, text)
+
+
+@pytest.mark.parametrize("space_in_gonb", [False, True])
+def test_read_simple_gonb_cell_with_double_percent(
+ space_in_gonb,
+ go_percent="""// ---
+// jupyter:
+// kernelspec:
+// display_name: Go (gonb)
+// language: go
+// name: gonb
+// ---
+
+// %%
+//gonb:%%
+fmt.Printf("Hello World!")
+""",
+):
+ """The cell marker should have the same indentation as the first code line. See issue #562"""
+ if space_in_gonb:
+ go_percent = go_percent.replace("//gonb:%%", "// gonb:%%")
+ nb = jupytext.reads(go_percent, fmt="go:percent")
+ assert len(nb.cells) == 1
+ (cell,) = nb.cells
+ assert cell.cell_type == "code", cell.cell_type
+ assert (
+ cell.source
+ == """%%
+fmt.Printf("Hello World!")"""
+ )
+
+
+def test_write_simple_gonb_cell_with_double_percent(
+ no_jupytext_version_number,
+ go_percent="""// ---
+// jupyter:
+// kernelspec:
+// display_name: Go (gonb)
+// language: go
+// name: gonb
+// ---
+
+// %%
+//gonb:%%
+fmt.Printf("Hello World!")
+""",
+):
+ """The cell marker should have the same indentation as the first code line. See issue #562"""
+ nb = jupytext.reads(go_percent, fmt="go:percent")
+ go = jupytext.writes(nb, fmt="go:percent")
+ compare(go, go_percent)