Launch a specific file using the Run button in the drop-down menu

Describe your feature request
When you right-click in the code editor, select “Run” in the drop-down menu to launch the currently open file.

An example of what it might look like:

image

What problem(s) would this feature solve?
It is inconvenient to constantly open the .replit file and change the Run launched by the green button in it file.

This feature would speed up the process of launching various files.

Also this function would be more convenient than this:

Explain what you were trying to do when you came across the problem leading to this feature request
I wanted to run the file test.py to test one of the functions of your project.

2 Likes

Interesting that the previous feature request was closed without the feature being implemented.

4 Likes

Alternative “solution”

Why not create multiple repls? It’s good that background stuff like code intelligence, which take up RAM, can instead balance their usage between multiple repls.
New Nix modules allow to reduce the amount of storage taken on new repls, so that’s not a problem. Dependencies taking up storage on multiple repls? Use Nix packages instead. Need to share code between programs? Create a package and put it on Nix.

Not helpful!

Besides the obvious inconvenience: replit’s Nix index is always behind, so you may not have the package or version you want. Maybe this problem could be ~solved by adding a restricted set of packages that are popular on Replit to nixmodules, which is probably easier for Replit to maintain than whole Nix channels. Users could contribute through PRs.

Clarify OP’s needs

I’m guessing that @midvok always edits a file before wanting to run it :person_shrugging: Also, unlike @midvok, @KAlexK wants the main run to be separated from an option to run a single file.

Workaround implementation

Here’s a JS script to put in the browser extension Code Injector, on URL pattern replit\.com/@\w*/(?!.+\?(?:lite|v)=). It maps Ctrl' to run the open file. By ' I mean whatever key is on the left of Enter on your keyboard layout. It uses the .replit file opened in the workspace, so it’d be more efficient if I manage to implement this in an extension.

runButton=__next.querySelector("[data-cy='ws-run-btn']>*")
toggleRun=runButton.click.bind(runButton)
queryMain=this["main-content"].querySelector.bind(this["main-content"])
querySidebar=this["sidebar-section-content-files"].querySelector.bind(this["sidebar-section-content-files"])
onkeyup=({ctrlKey,code})=>{if(ctrlKey&&code=="Quote"){let
replitEditor=queryMain(`:scope>[role=tabpanel]>*>:nth-child(2)>:nth-child(2)
[data-cy$='-.replit']
.cm-scroller>.cm-content`)
const
openedTab=queryMain(`.os-viewport
[aria-selected^=t]>span`),{textContent}=openedTab,stateElement=runButton.querySelector(":scope>span")
if(replitEditor)runOpenFile()
else{try{querySidebar("[role=tree]>[aria-label='.replit").click()}catch(err){alert("[focused file runner|opening .replit] Please show hidden files!")
throw ".replit file not in sidebar tree"}
let
editorSetter=new
MutationObserver(([{addedNodes:[node]}])=>{replitEditor=node.querySelector(`:scope>*>:nth-child(2)>:nth-child(2)
.cm-scroller>.cm-content`)
let
runWhenLoaded=new
MutationObserver(([{attributeName}])=>{openedTab.parentNode.parentNode.parentNode.nextSibling.querySelector(":scope>*>*").click()
if(attributeName=="aria-readonly"){for(let
it
of
querySidebar("[role=tree").getElementsByTagName("div"))if(it.ariaLabel==textContent){it.click()
break}
runOpenFile()
runWhenLoaded.disconnect()}})
runWhenLoaded.observe(replitEditor,{attributes:true})})
editorSetter.observe(this["main-content"],{childList:true})}function
runOpenFile(){let{view}=replitEditor.cmView,{0:oldEntrypoint,indices:[[from,to]]}=/(?<=^entrypoint\s*=\s*(['"])).+(?=\1)/md.exec(view.state.doc)
pushEntrypoint(to,textContent)
toggleRun()
if(stateElement.textContent!="Run")onceRunState(false,toggleRun)
onceRunState(true,partial(setTimeout,partial(pushEntrypoint,from+textContent.length,oldEntrypoint),6e2))
function
onceRunState(state,callback){const
observer=new
MutationObserver(([{target:{data}}])=>{if(data.startsWith("R")!=state){callback()
observer.disconnect()}})
observer.observe(stateElement,{characterData:true,subtree:true})}function
pushEntrypoint(to,insert){view.dispatch({changes:{from,to,insert}})}}}}
function
partial(func,...args){return func.bind(null,...args)}
2 Likes

The solution you proposed would be inconvenient, since I wanted to test the function of one of my repl files.

To test the function of one of the repl files using your method, after creating a new repl, I would have to transfer to a new repl the file whose function I wanted to test.

Therefore, I consider this solution unsuitable for my case.

the script workaround doesn’t work anymore :slightly_frowning_face: I’ll have to change a few CSS selectors (like the one for openedTab) and hopefully that’s it. But can anyone beat me to it? @python660 maybe :smiley: ?

2 Likes

Ill try but keep in mind that I am ten hours late and its 11:59 PM rn :slight_smile: .

The problem with your code is as follows:
queryMain(`.os-viewport [aria-selected^=t]>span`) doesn’t exist

To solve this, use the syntax for descendents to select a child somewhere in the parent: queryMain(`.os-viewport [aria-selected^=t] span`)

EDIT 2:
Here is the finalized code:

runButton = __next.querySelector("[data-cy='ws-run-btn']>*")
toggleRun = runButton.click.bind(runButton)
queryMain = this["main-content"].querySelector.bind(this["main-content"])
querySidebar = this["sidebar-section-content-files"].querySelector.bind(this["sidebar-section-content-files"])
onkeyup = ({
    ctrlKey,
    code
}) => {
    if (ctrlKey && code == "Quote") {
        let
            replitEditor = queryMain(`:scope>[role=tabpanel]>*>:nth-child(2)>:nth-child(2)
[data-cy$='-.replit']
.cm-scroller>.cm-content`)
        const
            openedTab = queryMain(`.os-viewport
[aria-selected^=t] span`),
            {
                textContent
            } = openedTab,
            stateElement = runButton.querySelector(":scope>span")
        if (replitEditor) runOpenFile()
        else {
            try {
                querySidebar("[role=tree]>[aria-label='.replit").click()
            } catch (err) {
                alert("[focused file runner|opening .replit] Please show hidden files!")
                throw ".replit file not in sidebar tree"
            }
            let
                editorSetter = new
            MutationObserver(([{
                addedNodes: [node]
            }]) => {
                replitEditor = node.querySelector(`:scope>*>:nth-child(2)>:nth-child(2)
.cm-scroller>.cm-content`)
                let
                    runWhenLoaded = new
                MutationObserver(([{
                    attributeName
                }]) => {
                    openedTab.parentNode.parentNode.parentNode.nextSibling.querySelector(":scope>*>*").click()
                    if (attributeName == "aria-readonly") {
                        for (let
                                it of
                                querySidebar("[role=tree").getElementsByTagName("div"))
                            if (it.ariaLabel == textContent) {
                                it.click()
                                break
                            }
                        runOpenFile()
                        runWhenLoaded.disconnect()
                    }
                })
                runWhenLoaded.observe(replitEditor, {
                    attributes: true
                })
            })
            editorSetter.observe(this["main-content"], {
                childList: true
            })
        }

        function
        runOpenFile() {
            let {
                view
            } = replitEditor.cmView, {
                0: oldEntrypoint,
                indices: [
                    [from, to]
                ]
            } = /(?<=^entrypoint\s*=\s*(['"])).+(?=\1)/md.exec(view.state.doc)
            pushEntrypoint(to, textContent)
            toggleRun()
            if (stateElement.textContent != "Run") onceRunState(false, toggleRun)
            onceRunState(true, partial(setTimeout, partial(pushEntrypoint, from + textContent.length, oldEntrypoint), 6e2))

            function
            onceRunState(state, callback) {
                const
                    observer = new
                MutationObserver(([{
                    target: {
                        data
                    }
                }]) => {
                    if (data.startsWith("R") != state) {
                        callback()
                        observer.disconnect()
                    }
                })
                observer.observe(stateElement, {
                    characterData: true,
                    subtree: true
                })
            }

            function
            pushEntrypoint(to, insert) {
                view.dispatch({
                    changes: {
                        from,
                        to,
                        insert
                    }
                })
            }
        }
    }
}

function
partial(func, ...args) {
    return func.bind(null, ...args)
}

Paste this into the inspect element console and have fun!

@UMARismyname beat you to it :wink:

1 Like