diff --git a/lua/cosmic/lsp/autocomplete.lua b/lua/cosmic/lsp/autocomplete.lua
index edd12df..4673c30 100644
--- a/lua/cosmic/lsp/autocomplete.lua
+++ b/lua/cosmic/lsp/autocomplete.lua
@@ -1,13 +1,19 @@
 local cmp = require('cmp')
+local luasnip = require('luasnip')
 
 vim.cmd([[
 autocmd FileType TelescopePrompt lua require('cmp').setup.buffer { enabled = false }
 ]])
 
+local has_words_before = function()
+  local line, col = unpack(vim.api.nvim_win_get_cursor(0))
+  return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match('%s') == nil
+end
+
 cmp.setup({
   snippet = {
     expand = function(args)
-      require'luasnip'.lsp_expand(args.body)
+      luasnip.lsp_expand(args.body)
     end,
   },
   mapping = {
@@ -19,20 +25,32 @@ cmp.setup({
       behavior = cmp.ConfirmBehavior.Replace,
       select = true,
     }),
-    ['<Tab>'] = function(fallback)
+    ['<Tab>'] = cmp.mapping(function(fallback)
       if cmp.visible() then
         cmp.select_next_item()
+      elseif luasnip.expand_or_jumpable() then
+        luasnip.expand_or_jump()
+      elseif has_words_before() then
+        cmp.complete()
       else
         fallback()
       end
-    end,
-    ['<S-Tab>'] = function(fallback)
+    end, {
+      'i',
+      's',
+    }),
+    ['<S-Tab>'] = cmp.mapping(function(fallback)
       if cmp.visible() then
         cmp.select_prev_item()
+      elseif luasnip.jumpable(-1) then
+        luasnip.jump(-1)
       else
         fallback()
       end
-    end,
+    end, {
+      'i',
+      's',
+    }),
   },
   documentation = {
     border = 'single',
@@ -43,10 +61,10 @@ cmp.setup({
   },
   sources = {
     { name = 'nvim_lsp' },
+    { name = 'luasnip' },
     { name = 'buffer' },
     { name = 'nvim_lua' },
     { name = 'path' },
-    { name = 'luasnip' },
   },
   formatting = {
     format = require('lspkind').cmp_format({