diff --git a/plugins/markdown/core/resources/META-INF/plugin.xml b/plugins/markdown/core/resources/META-INF/plugin.xml
index 14f8627a89ce..c97af1427e6d 100644
--- a/plugins/markdown/core/resources/META-INF/plugin.xml
+++ b/plugins/markdown/core/resources/META-INF/plugin.xml
@@ -129,6 +129,19 @@
level="WARNING"
implementationClass="org.intellij.plugins.markdown.editor.tables.inspections.MarkdownTablePipeInCodeSpanInspection"/>
+
+ Markdown
+ org.intellij.plugins.markdown.editor.tables.intentions.ReformatTableIntention
+ messages.MarkdownBundle
+ markdown.intention.category
+
+
+ Markdown
+ org.intellij.plugins.markdown.editor.tables.intentions.FixCellAlignmentIntention
+ messages.MarkdownBundle
+ markdown.intention.category
+
+
Markdown
org.intellij.plugins.markdown.editor.tables.intentions.MarkdownInsertTableColumnIntention$InsertBefore
diff --git a/plugins/markdown/core/resources/intentionDescriptions/FixCellAlignmentIntention/after.md.template b/plugins/markdown/core/resources/intentionDescriptions/FixCellAlignmentIntention/after.md.template
new file mode 100644
index 000000000000..fd5695d2e258
--- /dev/null
+++ b/plugins/markdown/core/resources/intentionDescriptions/FixCellAlignmentIntention/after.md.template
@@ -0,0 +1,3 @@
+| Value |
+|------:|
+| 1 |
diff --git a/plugins/markdown/core/resources/intentionDescriptions/FixCellAlignmentIntention/before.md.template b/plugins/markdown/core/resources/intentionDescriptions/FixCellAlignmentIntention/before.md.template
new file mode 100644
index 000000000000..d307825d2b73
--- /dev/null
+++ b/plugins/markdown/core/resources/intentionDescriptions/FixCellAlignmentIntention/before.md.template
@@ -0,0 +1,3 @@
+| Value |
+|------:|
+| 1 |
diff --git a/plugins/markdown/core/resources/intentionDescriptions/FixCellAlignmentIntention/description.html b/plugins/markdown/core/resources/intentionDescriptions/FixCellAlignmentIntention/description.html
new file mode 100644
index 000000000000..6790cd1d0934
--- /dev/null
+++ b/plugins/markdown/core/resources/intentionDescriptions/FixCellAlignmentIntention/description.html
@@ -0,0 +1,5 @@
+
+
+Adjusts the current table cell to match its column alignment.
+
+
diff --git a/plugins/markdown/core/resources/intentionDescriptions/ReformatTableIntention/after.md.template b/plugins/markdown/core/resources/intentionDescriptions/ReformatTableIntention/after.md.template
new file mode 100644
index 000000000000..ef04ac5e30e2
--- /dev/null
+++ b/plugins/markdown/core/resources/intentionDescriptions/ReformatTableIntention/after.md.template
@@ -0,0 +1,3 @@
+| Name | Value |
+|-------|-------|
+| first | 1 |
diff --git a/plugins/markdown/core/resources/intentionDescriptions/ReformatTableIntention/before.md.template b/plugins/markdown/core/resources/intentionDescriptions/ReformatTableIntention/before.md.template
new file mode 100644
index 000000000000..d72f03730061
--- /dev/null
+++ b/plugins/markdown/core/resources/intentionDescriptions/ReformatTableIntention/before.md.template
@@ -0,0 +1,3 @@
+| Name | Value |
+|---|---|
+| first | 1 |
diff --git a/plugins/markdown/core/resources/intentionDescriptions/ReformatTableIntention/description.html b/plugins/markdown/core/resources/intentionDescriptions/ReformatTableIntention/description.html
new file mode 100644
index 000000000000..74d12cdfa3e3
--- /dev/null
+++ b/plugins/markdown/core/resources/intentionDescriptions/ReformatTableIntention/description.html
@@ -0,0 +1,5 @@
+
+
+Formats all columns in the current Markdown table.
+
+
diff --git a/plugins/markdown/core/src/org/intellij/plugins/markdown/settings/MarkdownCodeInsightSettings.kt b/plugins/markdown/core/src/org/intellij/plugins/markdown/settings/MarkdownCodeInsightSettings.kt
index 5c3f88eb6797..aa76d58e4bed 100644
--- a/plugins/markdown/core/src/org/intellij/plugins/markdown/settings/MarkdownCodeInsightSettings.kt
+++ b/plugins/markdown/core/src/org/intellij/plugins/markdown/settings/MarkdownCodeInsightSettings.kt
@@ -16,14 +16,14 @@ import org.jetbrains.annotations.Nls
storages = [(Storage("markdown.xml"))])
class MarkdownCodeInsightSettings: SimplePersistentStateComponent(State()) {
class State: BaseState() {
- var reformatTablesOnType: Boolean by property(true)
+ var reformatTablesOnType: Boolean by property(false)
var insertHtmlLineBreakInsideTables: Boolean by property(true)
var insertNewTableRowOnShiftEnter: Boolean by property(true)
var useTableCellNavigation: Boolean by property(true)
var adjustListIndentation: Boolean by property(true)
var smartEnterAndBackspace: Boolean by property(true)
var renumberListsOnType: Boolean by property(false)
- var listNumberingType by enum(ListNumberingType.SEQUENTIAL)
+ var listNumberingType: ListNumberingType by enum(ListNumberingType.SEQUENTIAL)
var enableFileDrop: Boolean by property(true)
}
diff --git a/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableColumnExpandTest.kt b/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableColumnExpandTest.kt
index e37ade8b0fac..297f753941a7 100644
--- a/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableColumnExpandTest.kt
+++ b/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableColumnExpandTest.kt
@@ -2,6 +2,9 @@
package org.intellij.plugins.markdown.editor.tables
import com.intellij.testFramework.LightPlatformCodeInsightTestCase
+import com.intellij.openapi.util.Disposer
+import org.intellij.plugins.markdown.settings.MarkdownCodeInsightSettings
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -9,6 +12,14 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
@Suppress("MarkdownIncorrectTableFormatting")
class MarkdownTableColumnExpandTest: LightPlatformCodeInsightTestCase() {
+ @Before
+ fun enableTableReformatting() {
+ val settings = MarkdownCodeInsightSettings.getInstance()
+ val old = settings.state.reformatTablesOnType
+ settings.state.reformatTablesOnType = true
+ Disposer.register(testRootDisposable) { settings.state.reformatTablesOnType = old }
+ }
+
@Test
fun `test right after cell content`() {
// language=Markdown
diff --git a/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableColumnShrinkTest.kt b/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableColumnShrinkTest.kt
index 2464624c7a23..3b0bb7351c58 100644
--- a/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableColumnShrinkTest.kt
+++ b/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableColumnShrinkTest.kt
@@ -1,7 +1,10 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.intellij.plugins.markdown.editor.tables
+import com.intellij.openapi.util.Disposer
import com.intellij.testFramework.LightPlatformCodeInsightTestCase
+import org.intellij.plugins.markdown.settings.MarkdownCodeInsightSettings
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -9,6 +12,14 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
@Suppress("MarkdownIncorrectTableFormatting")
class MarkdownTableColumnShrinkTest: LightPlatformCodeInsightTestCase() {
+ @Before
+ fun enableTableReformatting() {
+ val settings = MarkdownCodeInsightSettings.getInstance()
+ val old = settings.state.reformatTablesOnType
+ settings.state.reformatTablesOnType = true
+ Disposer.register(testRootDisposable) { settings.state.reformatTablesOnType = old }
+ }
+
@Test
fun `test right after cell content`() {
// language=Markdown
diff --git a/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableColumnShrinkWithFullWidthTest.kt b/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableColumnShrinkWithFullWidthTest.kt
index 05669b55f3af..2cbebbdbe9c2 100644
--- a/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableColumnShrinkWithFullWidthTest.kt
+++ b/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableColumnShrinkWithFullWidthTest.kt
@@ -1,7 +1,10 @@
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.intellij.plugins.markdown.editor.tables
+import com.intellij.openapi.util.Disposer
import com.intellij.testFramework.LightPlatformCodeInsightTestCase
+import org.intellij.plugins.markdown.settings.MarkdownCodeInsightSettings
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@@ -9,6 +12,14 @@ import org.junit.runners.JUnit4
@RunWith(JUnit4::class)
@Suppress("MarkdownIncorrectTableFormatting")
class MarkdownTableColumnShrinkWithFullWidthTest: LightPlatformCodeInsightTestCase() {
+ @Before
+ fun enableTableReformatting() {
+ val settings = MarkdownCodeInsightSettings.getInstance()
+ val old = settings.state.reformatTablesOnType
+ settings.state.reformatTablesOnType = true
+ Disposer.register(testRootDisposable) { settings.state.reformatTablesOnType = old }
+ }
+
@Test
fun `test backspace cjk character`() {
// language=Markdown
diff --git a/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableTypingTest.kt b/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableTypingTest.kt
new file mode 100644
index 000000000000..33873e5fd9a2
--- /dev/null
+++ b/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/MarkdownTableTypingTest.kt
@@ -0,0 +1,458 @@
+// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package org.intellij.plugins.markdown.editor.tables
+
+import com.intellij.application.options.CodeStyle
+import com.intellij.application.options.codeStyle.excludedFiles.GlobPatternDescriptor
+import com.intellij.openapi.util.Disposer
+import com.intellij.psi.PsiFile
+import com.intellij.testFramework.LightPlatformCodeInsightTestCase
+import org.intellij.plugins.markdown.settings.MarkdownCodeInsightSettings
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+@Suppress("MarkdownIncorrectTableFormatting")
+class MarkdownTableTypingTest: LightPlatformCodeInsightTestCase() {
+ @Before
+ fun enableTableReformatting() {
+ val settings = MarkdownCodeInsightSettings.getInstance()
+ val old = settings.state.reformatTablesOnType
+ settings.state.reformatTablesOnType = true
+ Disposer.register(testRootDisposable) { settings.state.reformatTablesOnType = old }
+ }
+
+ @Test
+ fun `test typing in non-last column reformats the table`() {
+ // language=Markdown
+ val before = """
+ | a |malformed| c |
+ |---|---|---|
+ | 1 |y| 2 |
+ """.trimIndent()
+
+ // language=Markdown
+ val after = """
+ | a |malformed| c |
+ |----|---|---|
+ | 1x |y| 2 |
+ """.trimIndent()
+ doTest(before, after, 1, "x")
+ }
+
+ @Test
+ fun `test typing in last column reformats the table`() {
+ // language=Markdown
+ val before = """
+ | a |malformed| c |
+ |---|---|---|
+ | 1 |y| 2 |
+ """.trimIndent()
+
+ // language=Markdown
+ val after = """
+ | a |malformed| c |
+ |---|---|----|
+ | 1 |y| 2x |
+ """.trimIndent()
+ doTest(before, after, 1, "x")
+ }
+
+ @Test
+ fun `test right after cell content`() {
+ // language=Markdown
+ doTest(
+ """
+ | none | none |
+ |------|------|
+ | a | asd |
+ """.trimIndent(),
+ """
+ | none | none |
+ |-------|------|
+ | a | asd |
+ """.trimIndent()
+ )
+ }
+
+ @Test
+ fun `test between spaces on the right side`() {
+ // language=Markdown
+ doTest(
+ """
+ | none | none |
+ |------|------|
+ | a | asd |
+ """.trimIndent(),
+ """
+ | none | none |
+ |-------|------|
+ | a | asd |
+ """.trimIndent()
+ )
+ }
+
+ @Test
+ fun `test just before right pipe`() {
+ // language=Markdown
+ doTest(
+ """
+ | none | none |
+ |------|------|
+ | a | asd |
+ """.trimIndent(),
+ """
+ | none | none |
+ |-------|------|
+ | a | asd |
+ """.trimIndent()
+ )
+ }
+
+ @Test
+ fun `test in separator`() {
+ doTest(
+ """
+ | none | none |
+ |------|------|
+ | a | asd |
+ """.trimIndent(),
+ """
+ | none | none |
+ |-------|------|
+ | a | asd |
+ """.trimIndent(),
+ string = "-"
+ )
+ }
+
+ @Test
+ fun `test in separator with colon`() {
+ doTest(
+ """
+ | none | none |
+ |------|------|
+ | a | asd |
+ """.trimIndent(),
+ """
+ | none | none |
+ |:------|------|
+ | a | asd |
+ """.trimIndent(),
+ string = ":"
+ )
+ }
+
+ @Test
+ fun `test with right alignment`() {
+ // language=Markdown
+ val before = """
+ | right |
+ | ---: |
+ | some |
+ """.trimIndent()
+ // language=Markdown
+ val after = """
+ | right |
+ |-------:|
+ | some |
+ """.trimIndent()
+ doTest(before, after)
+ }
+
+ @Test
+ fun `test typing with right alignment`() {
+ // language=Markdown
+ val before = """
+ | right |
+ |------:|
+ | |
+ """.trimIndent()
+ // language=Markdown
+ val after = """
+ | right |
+ |------:|
+ | some |
+ """.trimIndent()
+ doTest(before, after, string = "some")
+ }
+
+ @Test
+ fun `test typing with right alignment and spaces`() {
+ // language=Markdown
+ val before = """
+ | right |
+ |------:|
+ | |
+ """.trimIndent()
+ // language=Markdown
+ val after = """
+ | right |
+ |-------------:|
+ | some content |
+ """.trimIndent()
+ doTest(before, after, string = "some content")
+ }
+
+ @Test
+ fun `test typing with left alignment`() {
+ // language=Markdown
+ val before = """
+ | left |
+ |-----:|
+ | |
+ """.trimIndent()
+ // language=Markdown
+ val after = """
+ | left |
+ |-----:|
+ | some |
+ """.trimIndent()
+ doTest(before, after, string = "some")
+ }
+
+ @Test
+ fun `test typing with left alignment and spaces`() {
+ // language=Markdown
+ val before = """
+ | left |
+ |-----:|
+ | |
+ """.trimIndent()
+ // language=Markdown
+ val after = """
+ | left |
+ |-------------:|
+ | some content |
+ """.trimIndent()
+ doTest(before, after, string = "some content")
+ }
+
+ @Test
+ fun `test typing with center alignment`() {
+ // language=Markdown
+ val before = """
+ | center |
+ |:------:|
+ | |
+ """.trimIndent()
+ // language=Markdown
+ val after = """
+ | center |
+ |:------:|
+ | some |
+ """.trimIndent()
+ doTest(before, after, string = "some")
+ }
+
+ @Test
+ fun `test typing with center alignment and ends with space`() {
+ // language=Markdown
+ val before = """
+ | center |
+ |:------:|
+ | |
+ """.trimIndent()
+ // language=Markdown
+ val after = """
+ | center |
+ |:------:|
+ | ssome |
+ """.trimIndent()
+ doTest(before, after, string = "ssome ")
+ }
+
+ @Test
+ fun `test typing in empty cell`() {
+ // language=Markdown
+ val before = """
+ ||
+ |-|
+ ||
+ """.trimIndent()
+ // language=Markdown
+ val after = """
+ | |
+ |------|
+ | some |
+ """.trimIndent()
+ doTest(before, after, string = "some")
+ }
+
+ @Test
+ fun `test typing space in cell with two spaces`() {
+ // language=Markdown
+ val before = """
+ | |
+ |--|
+ | |
+ """.trimIndent()
+ // language=Markdown
+ val after = """
+ | |
+ |---|
+ | |
+ """.trimIndent()
+ doTest(before, after, string = " ")
+ }
+
+ @Test
+ fun `test no column expand`() {
+ // language=Markdown
+ val content = """
+ | some |
+ |------|
+ | |
+ """.trimIndent()
+ // language=Markdown
+ val expected = """
+ | some |
+ |------|
+ | some |
+ """.trimIndent()
+ configureFromFileText("some.md", content)
+ runWithDisabledFormatting(file) {
+ type("some")
+ checkResultByText(expected)
+ }
+ }
+
+ @Test
+ fun `test no column shrink`() {
+ // language=Markdown
+ val content = """
+ | some |
+ |--------------|
+ | some text |
+ """.trimIndent()
+ // language=Markdown
+ val expected = """
+ | some |
+ |--------------|
+ | some tex |
+ """.trimIndent()
+ configureFromFileText("some.md", content)
+ runWithDisabledFormatting(file) {
+ backspace()
+ checkResultByText(expected)
+ }
+ }
+
+ @Test
+ fun `test no alignment correction`() {
+ // language=Markdown
+ val content = """
+ | some content |
+ |:------------:|
+ | |
+ """.trimIndent()
+ // language=Markdown
+ val expected = """
+ | some content |
+ |:------------:|
+ | some |
+ """.trimIndent()
+ configureFromFileText("some.md", content)
+ runWithDisabledFormatting(file) {
+ type("some")
+ checkResultByText(expected)
+ }
+ }
+
+ @Test
+ fun `test no column expand when reformat on type is disabled`() {
+ // language=Markdown
+ val content = """
+ | some |
+ |------|
+ | |
+ """.trimIndent()
+ // language=Markdown
+ val expected = """
+ | some |
+ |------|
+ | some |
+ """.trimIndent()
+ configureFromFileText("some.md", content)
+ runWithReformatOnTypeDisabled {
+ type("some")
+ checkResultByText(expected)
+ }
+ }
+
+ @Test
+ fun `test no column shrink when reformat on type is disabled`() {
+ // language=Markdown
+ val content = """
+ | some |
+ |--------------|
+ | some text |
+ """.trimIndent()
+ // language=Markdown
+ val expected = """
+ | some |
+ |--------------|
+ | some tex |
+ """.trimIndent()
+ configureFromFileText("some.md", content)
+ runWithReformatOnTypeDisabled {
+ backspace()
+ checkResultByText(expected)
+ }
+ }
+
+ @Test
+ fun `test no alignment correction when reformat on type is disabled`() {
+ // language=Markdown
+ val content = """
+ | some content |
+ |:------------:|
+ | |
+ """.trimIndent()
+ // language=Markdown
+ val expected = """
+ | some content |
+ |:------------:|
+ | some |
+ """.trimIndent()
+ configureFromFileText("some.md", content)
+ runWithReformatOnTypeDisabled {
+ type("some")
+ checkResultByText(expected)
+ }
+ }
+
+ private fun runWithReformatOnTypeDisabled(block: () -> Unit) {
+ val settings = MarkdownCodeInsightSettings.getInstance()
+ val old = settings.state.reformatTablesOnType
+ settings.state.reformatTablesOnType = false
+ try {
+ block.invoke()
+ }
+ finally {
+ settings.state.reformatTablesOnType = old
+ }
+ }
+
+ private fun runWithDisabledFormatting(file: PsiFile, block: () -> Unit) {
+ val settings = CodeStyle.getSettings(file)
+ val old = settings.excludedFiles.descriptors.toList()
+ settings.excludedFiles.addDescriptor(GlobPatternDescriptor("*.md"))
+ try {
+ block.invoke()
+ }
+ finally {
+ settings.excludedFiles.apply {
+ clear()
+ old.forEach(this::addDescriptor)
+ }
+ }
+ }
+
+ private fun doTest(content: String, expected: String, count: Int = 1, string: String = " ") {
+ configureFromFileText("some.md", content)
+ type(string.repeat(count))
+ checkResultByText(expected)
+ }
+}
diff --git a/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/inspections/MarkdownIncorrectTableFormattingInspectionQuickFixTest.kt b/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/inspections/MarkdownIncorrectTableFormattingInspectionQuickFixTest.kt
index 64c276adf672..e5a88fab1efb 100644
--- a/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/inspections/MarkdownIncorrectTableFormattingInspectionQuickFixTest.kt
+++ b/plugins/markdown/test/src/org/intellij/plugins/markdown/editor/tables/inspections/MarkdownIncorrectTableFormattingInspectionQuickFixTest.kt
@@ -19,6 +19,21 @@ class MarkdownIncorrectTableFormattingInspectionQuickFixTest: LightPlatformCodeI
private val reformatIntentionFixText
get() = MarkdownBundle.message("markdown.reformat.table.intention.text")
+ private val fixCellAlignmentIntentionText
+ get() = MarkdownBundle.message("markdown.fix.cell.alignment.intention.text")
+
+ @Test
+ fun `reformat intention is available without inspection`() {
+ myFixture.configureByText("some.md", "| first | second |\n|---|---|")
+ assertNotNull(myFixture.availableIntentions.find { it.text == reformatIntentionFixText })
+ }
+
+ @Test
+ fun `fix cell alignment intention is available without inspection`() {
+ myFixture.configureByText("some.md", "| first |\n|------:|\n| some |")
+ assertNotNull(myFixture.availableIntentions.find { it.text == fixCellAlignmentIntentionText })
+ }
+
@Test
fun `works with incorrectly formatted cell`() {
// language=Markdown