diff --git a/script/core/completion.lua b/script/core/completion.lua
index ba48045131a11de26a40057f3f6ce678d7bfeb27..d4f773686de6277797191b914b027640e1875b17 100644
--- a/script/core/completion.lua
+++ b/script/core/completion.lua
@@ -197,7 +197,7 @@ local function buildDesc(source)
     md:add('md',  hover.description)
     md:splitLine()
     md:add('lua', getSnip(source))
-    return md:string()
+    return md
 end
 
 local function buildFunction(results, source, value, oop, data)
@@ -385,13 +385,15 @@ local function checkModule(ast, word, offset, results)
                     },
                 },
                 id     = stack(function ()
+                    local md = markdown()
+                    md:add('md', lang.script('COMPLETION_IMPORT_FROM', ('[%s](%s)'):format(
+                        workspace.getRelativePath(uri),
+                        uri
+                    )))
+                    md:add('md', buildDesc(targetSource))
                     return {
                         detail      = buildDetail(targetSource),
-                        description = lang.script('COMPLETION_IMPORT_FROM', ('[%s](%s)'):format(
-                            workspace.getRelativePath(uri),
-                            uri
-                        ))
-                            .. '\n' .. buildDesc(targetSource),
+                        description = md,
                         --additionalTextEdits = buildInsertRequire(ast, originUri, stemName),
                     }
                 end)
diff --git a/script/core/hover/description.lua b/script/core/hover/description.lua
index b58a08b7c2964b7fb8d5c6773da1ed2300be5662..afeb1bb963e2fe18cbadf7dbcc1d548a018ae9f5 100644
--- a/script/core/hover/description.lua
+++ b/script/core/hover/description.lua
@@ -50,7 +50,7 @@ local function asStringInRequire(source, literal)
             table.sort(shows)
             local md = markdown()
             md:add('md', table.concat(shows, '\n'))
-            return md:string()
+            return md
         end
     end
 end
@@ -68,7 +68,7 @@ local function asStringView(source, literal)
         end
         local md = markdown()
         md:add('txt', view)
-        return md:string()
+        return md
     end
 end
 
@@ -314,7 +314,7 @@ local function getFunctionComment(source)
     local md = markdown()
     md:add('md', comments)
     md:add('lua', enums)
-    return md:string()
+    return md
 end
 
 local function tryDocComment(source)
diff --git a/script/core/hover/label.lua b/script/core/hover/label.lua
index 0d2bcf6f754e22b908fe3b881fb86ff6e29d838e..a29cf672ac700b96936259d9e52f1c210d2469bc 100644
--- a/script/core/hover/label.lua
+++ b/script/core/hover/label.lua
@@ -5,7 +5,6 @@ local buildTable  = require 'core.hover.table'
 local infer       = require 'core.infer'
 local vm          = require 'vm'
 local util        = require 'utility'
-local searcher    = require 'core.searcher'
 local lang        = require 'language'
 local config      = require 'config'
 local files       = require 'files'
diff --git a/script/provider/markdown.lua b/script/provider/markdown.lua
index c5765571cae64492acce85494218bf92c14d1929..5e564a40ee0262d9d6039ed8789b85b41506c9e2 100644
--- a/script/provider/markdown.lua
+++ b/script/provider/markdown.lua
@@ -4,6 +4,10 @@ mt.__name = 'markdown'
 
 mt._splitLine = false
 
+function mt:__tostring()
+    return self:string()
+end
+
 local function checkSplitLine(self)
     if not self._splitLine then
         return
diff --git a/script/provider/provider.lua b/script/provider/provider.lua
index c416e7481e40a11d12931b326802839a700191d9..aebf733ea16ff7e39444efa165668e15965263c8 100644
--- a/script/provider/provider.lua
+++ b/script/provider/provider.lua
@@ -445,7 +445,7 @@ proto.on('textDocument/completion', function (params)
                 return t
             end)(),
             documentation    = res.description and {
-                value = res.description,
+                value = tostring(res.description),
                 kind  = 'markdown',
             },
         }
@@ -455,7 +455,7 @@ proto.on('textDocument/completion', function (params)
                 if resolved then
                     item.detail = resolved.detail
                     item.documentation = resolved.description and {
-                        value = resolved.description,
+                        value = tostring(resolved.description),
                         kind  = 'markdown',
                     }
                 end
@@ -491,7 +491,7 @@ proto.on('completionItem/resolve', function (item)
     end
     item.detail = resolved.detail or item.detail
     item.documentation = resolved.description and {
-        value = resolved.description,
+        value = tostring(resolved.description),
         kind  = 'markdown',
     } or item.documentation
     item.additionalTextEdits = resolved.additionalTextEdits and (function ()
@@ -545,7 +545,7 @@ proto.on('textDocument/signatureHelp', function (params)
             parameters      = parameters,
             activeParameter = result.index - 1,
             documentation   = result.description and {
-                value = result.description,
+                value = tostring(result.description),
                 kind  = 'markdown',
             },
         }
diff --git a/test/completion/init.lua b/test/completion/init.lua
index 419bde82c5a28112941969e492b1ee26ecc8414b..3536007abf448a0fae3d82f5b0d18cdfffe390b6 100644
--- a/test/completion/init.lua
+++ b/test/completion/init.lua
@@ -88,6 +88,9 @@ function TEST(script)
                     item[k] = nil
                 end
             end
+            if item.description then
+                item.description = tostring(item.description)
+            end
         end
         if IgnoreFunction then
             for i = #result, 1, -1 do
diff --git a/test/crossfile/completion.lua b/test/crossfile/completion.lua
index d393c8e806ea0ee9e5cad184fdadbbf79de0462f..e9a70199990550860d06cd2bdbfa1d84a3eb0941 100644
--- a/test/crossfile/completion.lua
+++ b/test/crossfile/completion.lua
@@ -116,7 +116,7 @@ function TEST(data)
             end
         end
         if item['description'] then
-            item['description'] = item['description']
+            item['description'] = tostring(item['description'])
                 : gsub('\r\n', '\n')
         end
     end
@@ -727,6 +727,7 @@ TEST {
             detail = 'function',
             description = [[
 从 [myfunc.lua](file:///myfunc.lua) 中导入
+
 ```lua
 function (a: any, b: any)
 ```]],
@@ -757,6 +758,7 @@ TEST {
             detail = 'function',
             description = [[
 从 [dir\myfunc.lua](file:///dir/myfunc.lua) 中导入
+
 ```lua
 function (a: any, b: any)
 ```]],
diff --git a/test/crossfile/hover.lua b/test/crossfile/hover.lua
index aaf69e7a9cf4fa68e04ec4ecdfd9586303c7204d..e673bc5f4c69ec3d6874db46c893407b37c6b1af 100644
--- a/test/crossfile/hover.lua
+++ b/test/crossfile/hover.lua
@@ -71,6 +71,9 @@ function TEST(expect)
     if hover.label then
         hover.label = hover.label:gsub('\r\n', '\n')
     end
+    if hover.description then
+        hover.description = tostring(hover.description)
+    end
     assert(eq(hover.label, expect.hover.label))
     assert(eq(hover.description, expect.hover.description))
 end