kayinfire

Test Code in The Next Available TMUX Tab

Nov 4th, 2025
13
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.93 KB | Source Code | 0 0
  1.  
  2. #!/bin/lua
  3. local has_posix, posix = pcall(require, "posix")
  4.  
  5. --[[
  6. We now have a new concern:
  7. Sometimes we want a to copy
  8. a terminal command, a test command, or a tmux command
  9. the distinctions between these are currently to be determined.
  10. what we do know for know is that all operations with respect to the system clipboard will reside one level of abstraction below the X11 object.
  11. as a matter of fact, a new object, SystemClipboard, will be a concrete class that will be used in X11
  12. ]]
  13. function TypeOfFile(file)
  14.     return {
  15.         check = function(self)
  16.             local file = self:activeTestFile(file)
  17.             local fileContainsTestCode = self:containsTestCode(file)
  18.             local programmingLanguageConcerningFile = self:programmingLanguage(file)
  19.             return {
  20.                 FilePath = file,
  21.                 ProgrammingLanguage = programmingLanguageConcerningFile,
  22.                 IsTestCode = fileContainsTestCode,
  23.             }
  24.         end,
  25.  
  26.         activeTestFile = function(self, filePath)
  27.             local file = io.open(filePath, "r")
  28.             local content = file:read("*a")
  29.             file:close()
  30.             return content
  31.         end,
  32.  
  33.         containsTestCode = function(self, filePath)
  34.             local fileName = string.match(filePath, "[^/]+$")
  35.             if fileName and string.find(fileName, "test") then
  36.                 return true
  37.             else
  38.                 return false
  39.             end
  40.         end,
  41.  
  42.         programmingLanguage = function(self)
  43.             local extensionToLanguage = {
  44.                 [".sh"] = "bash",
  45.                 [".bash"] = "bash",
  46.                 [".js"] = "javascript",
  47.                 [".mjs"] = "javascript",
  48.                 [".cjs"] = "javascript",
  49.                 [".java"] = "java",
  50.                 [".py"] = "python",
  51.                 [".lua"] = "lua",
  52.                 [".t"] = "perl",
  53.             }
  54.  
  55.             -- Extract file extension
  56.             local extension = file:match("%.([^%.]+)$")
  57.             if extension then
  58.                 extension = "." .. extension
  59.                 return extensionToLanguage[extension] or "Unknown"
  60.             else
  61.                 return "Unknown"
  62.             end
  63.         end,
  64.     }
  65. end
  66.  
  67. function AvailableTestingFrameworks()
  68.     return {
  69.         selectFrameworkFor = function(self, language)
  70.             local testFrameworks = self:testFrameworks()
  71.             return self:testingFrameworkRegardingLanguage(testFrameworks, language)
  72.         end,
  73.  
  74.         testFrameworks = function(self)
  75.             return {
  76.                 { "perl", { "prove -vv " } },
  77.                 { "lua", { "busted" } },
  78.                 { "javascript", { "mocha ", "jest " } },
  79.                 { "go", { "go test -v " } },
  80.                 { "c++", { "gtest ", "catch2 " } },
  81.                 { "php", { "phpunit " } },
  82.                 { "ruby", { "rspec ", "minitest " } },
  83.                 { "rust", { "cargo test -- --nocapture " } },
  84.                 { "java", { "mvn test ", "gradle test " } },
  85.                 { "c#", { "dotnet test " } },
  86.                 { "bash", { "bats " } },
  87.                 { "r", { "testthat::test_dir() " } },
  88.                 { "haskell", { "stack test ", "cabal test " } },
  89.             }
  90.         end,
  91.  
  92.         testingFrameworkRegardingLanguage = function(self, availableFrameworks, languageWithRespectToTestFile)
  93.             for i, framework in ipairs(availableFrameworks) do
  94.                 if framework[1] == languageWithRespectToTestFile then
  95.                     return framework[2][1]
  96.                 end
  97.             end
  98.             return nil
  99.         end,
  100.     }
  101. end
  102.  
  103. function TestCommand(dependencies)
  104.     return {
  105.         toBeExecutedInTMUX = function(self)
  106.             local file = self:fileProperties():check()
  107.             local testingFrameworkCommand = self:availableFrameworks():selectFrameworkFor(file.ProgrammingLanguage)
  108.             return self:constructedTerminalCommand(testingFrameworkCommand, file.FilePath)
  109.         end,
  110.  
  111.         fileProperties = function(self)
  112.             return dependencies[1]
  113.         end,
  114.  
  115.         availableFrameworks = function(self)
  116.             return dependencies[2]
  117.         end,
  118.  
  119.         constructedTerminalCommand = function(self, testingFrameworkCommand, testFile)
  120.             return string.format(
  121.                 "%s %s",
  122.                 -- "%s %s && listenForTabKey",
  123.                 testingFrameworkCommand:gsub("[\r\n]", ""),
  124.                 testFile:gsub("[\r\n]", "")
  125.             )
  126.         end,
  127.     }
  128. end
  129.  
  130. function TabKey()
  131.     return {
  132.         hasBeenPressedByUser = function(self)
  133.             if not has_posix then
  134.                 return false
  135.             end
  136.  
  137.             -- Check if input is available without blocking
  138.             local fd = posix.unistd.STDIN_FILENO
  139.             local readfds = posix.sys.select({ fd }, {}, {}, 0)
  140.  
  141.             if readfds and #readfds > 0 then
  142.                 local char = io.read(1)
  143.                 return char and char:byte() == 9
  144.             end
  145.  
  146.             return false
  147.         end,
  148.     }
  149. end
  150.  
  151. function X11(tabKey)
  152.     return {
  153.         userWantsToGoBackToProgrammingTab = function(self)
  154.             while true do
  155.                 if tabKey:hasBeenPressedByUser() then
  156.                     return true
  157.                 end
  158.                 posix.unistd.sleep(1)
  159.             end
  160.         end,
  161.  
  162.         execute = function(self, action)
  163.             local commandType = action[1]
  164.             if commandType == "copy" then
  165.                 self:copyCommandToClipboard(action[2])
  166.             elseif commandType == "paste" then
  167.                 self:pasteCommandInTerminal()
  168.             elseif commandType == "terminalCommand" then
  169.                 self:executeCommandInTerminal()
  170.             end
  171.         end,
  172.  
  173.         copyCommandToClipboard = function(self, testCommand)
  174.             -- Use io.popen to write directly to xsel
  175.             local pipe = io.popen("xsel -ib", "w")
  176.             if pipe then
  177.                 pipe:write(testCommand)
  178.                 pipe:close()
  179.             else
  180.             end
  181.         end,
  182.  
  183.         pasteCommandInTerminal = function(self)
  184.             os.execute("sleep 0.01")
  185.             os.execute("xdotool key ctrl+shift+v")
  186.         end,
  187.  
  188.         executeCommandInTerminal = function(self)
  189.             os.execute("sleep 0.01")
  190.             os.execute("xdotool key Return")
  191.         end,
  192.     }
  193. end
  194.  
  195. function Terminal(desktopEnvironment)
  196.     return {
  197.         executeCommandsGiven = function(self, testCommand)
  198.             self:changeTheTerminalDirectoryToTestFileDirectory(testCommand)
  199.             self:clearScreenBeforeExecutingTestCommand()
  200.             self:executeTestInTerminalTabAfterEnteringCommand(testCommand)
  201.         end,
  202.  
  203.         changeTheTerminalDirectoryToTestFileDirectory = function(self, testCommand)
  204.             local testDirectory = TestDirectory(testCommand)
  205.             ChangeDirectory(desktopEnvironment):given(testDirectory)
  206.         end,
  207.  
  208.         clearScreenBeforeExecutingTestCommand = function(self)
  209.             os.execute("xdotool key ctrl+l")
  210.         end,
  211.  
  212.         executeTestInTerminalTabAfterEnteringCommand = function(self, testCommand)
  213.             desktopEnvironment:execute({ "copy", testCommand })
  214.             desktopEnvironment:execute({ "paste" })
  215.             desktopEnvironment:execute({ "terminalCommand" })
  216.         end,
  217.     }
  218. end
  219.  
  220. function TestDirectory(command)
  221.     return {
  222.         withRespectToTestFile = function(self)
  223.             local testFile = self:testFileAbsoluteFilePath()
  224.             return self:testDirectoryPath(testFile)
  225.         end,
  226.  
  227.         testFileAbsoluteFilePath = function(self)
  228.             local parts = {}
  229.             for part in string.gmatch(command, "[^%s]+") do
  230.                 table.insert(parts, part)
  231.             end
  232.             return parts[2]
  233.         end,
  234.         testDirectoryPath = function(self, testFile)
  235.             return string.match(testFile, ".*/")
  236.         end,
  237.     }
  238. end
  239.  
  240. function ChangeDirectory(desktopEnvironment)
  241.     return {
  242.         given = function(self, testDirectory)
  243.             local cdCommand = string.format("cd %s", testDirectory:withRespectToTestFile())
  244.             self:enterChangeDirectoryCommand(cdCommand)
  245.             self:executeChangeDirectoryCommand()
  246.         end,
  247.  
  248.         enterChangeDirectoryCommand = function(self, cdCommand)
  249.             desktopEnvironment:execute({ "copy", cdCommand })
  250.             os.execute("sleep 0.01")
  251.             desktopEnvironment:execute({ "paste" })
  252.             os.execute("sleep 0.01")
  253.         end,
  254.  
  255.         executeChangeDirectoryCommand = function(self)
  256.             os.execute("xdotool key return")
  257.             os.execute("sleep 0.01")
  258.         end,
  259.     }
  260. end
  261.  
  262. function TMUX(tmuxDependencies)
  263.     return {
  264.         executeTestCommandInTestingTabGiven = function(self, testCommand)
  265.             local testCommand = testCommand:toBeExecutedInTMUX()
  266.             self:moveToTestTab()
  267.             self:closeProcessesInTestTab()
  268.             tmuxDependencies.Terminal:executeCommandsGiven(testCommand)
  269.             if tmuxDependencies.DesktopEnvironment:userWantsToGoBackToProgrammingTab() then
  270.                 self:moveToProgrammingTab()
  271.             end
  272.         end,
  273.  
  274.         moveToTestTab = function(self)
  275.             os.execute("tmux -L default next-window")
  276.         end,
  277.  
  278.         closeProcessesInTestTab = function(self)
  279.             TMUXEnvironment(tmuxDependencies.DesktopEnvironment):refreshWindow()
  280.         end,
  281.  
  282.         moveToProgrammingTab = function(self)
  283.             os.execute("sleep 0.01")
  284.             os.execute("xdotool key alt+m j")
  285.         end,
  286.     }
  287. end
  288.  
  289. function TMUXEnvironment(desktopEnvironment)
  290.     return {
  291.         refreshWindow = function(self)
  292.             self:openTMUXCommandLine()
  293.             self:enterRespawnCommandForTmux()
  294.             self:executeTMUXRespawnCommand()
  295.         end,
  296.  
  297.         openTMUXCommandLine = function(self)
  298.             os.execute("sleep 0.01")
  299.             os.execute("xdotool key alt+m")
  300.             os.execute("sleep 0.01")
  301.             os.execute("xdotool key colon")
  302.             os.execute("sleep 0.01")
  303.         end,
  304.  
  305.         enterRespawnCommandForTmux = function(self)
  306.             desktopEnvironment:execute({ "copy", "respawn-window -k" })
  307.             desktopEnvironment:execute({ "paste" })
  308.             os.execute("sleep 0.01")
  309.         end,
  310.  
  311.         executeTMUXRespawnCommand = function(self)
  312.             os.execute("xdotool key Return")
  313.             os.execute("sleep 0.01")
  314.         end,
  315.     }
  316. end
  317.  
  318. local fileFromNeovimBuffer = "~/activeTestFile.lua"
  319. local testCommandDependencies = { TypeOfFile(fileFromNeovimBuffer), AvailableTestingFrameworks() }
  320. local testCommand = TestCommand(testCommandDependencies)
  321. local tabKey = TabKey()
  322. local desktopEnvironment = X11(tabKey)
  323. local tmuxDependencies = { DesktopEnvironment = desktopEnvironment, Terminal = Terminal(desktopEnvironment) }
  324. TMUX(tmuxDependencies):executeTestCommandInTestingTabGiven(testCommand)
  325. os.exit(0)
  326.  
Advertisement
Add Comment
Please, Sign In to add comment