Setting Up the Zed Editor for Maya Python

Introduction

I have started using the Zed Editor a lot recently as it seems a lot easier and simpler to use that VSCode. As I have been doing some maya development I thought I would see how to set things up for Maya Python (and Maya Mel), and in particular how to send code to maya from the editor.

The Maya commandPort

The maya commandPort command opens up a socket to allow communication between a program and maya in the last few versions of maya there have been some issues with the commandPort command and the encoding has been causing issues. However this is now fixed and I amd using Maya 2025 and it is working well.

To get things working we need to open up a command port, I tend to do this using the userSetup.py file that maya reads on startup. This is located in the following folders per OS.

# Windows
%HOMEDRIVE%\%HOMEPATH%\Documents\maya\[version]\scripts
# Linux
~/maya/[version]/scripts
# Mac OSX
~/Library/Preferences/Autodesk/maya/[version]/scripts

In my case I am using a mac so I created the file userSetup.py in the folder ~/Library/Preferences/Autodesk/maya/2025

I added the following code to the file

import maya.cmds as cmds

cmds.evalDeferred("cmds.commandPort(name=':7001', sourceType='mel', echoOutput=False)")
cmds.evalDeferred("cmds.commandPort(name=':7002', sourceType='python', echoOutput=False)")

I use the evalDeferred command so that the rest of maya start up can happen before the ports are open.

For my setup I am going to use the ports 7001 for mel and 7002 for python.

We can do a quick test that this works by first re-starting maya (so the userSetup.py changes take effect) the using the nc - netcat command as follows

# note the \\n to escape the newline in the string.
echo 'print("hello maya\\n")' | nc localhost 7001
echo 'print("hello maya\\n")' | nc localhost 7002

This should print hello maya in the script editor.

Sending Data to Maya

Whilst it is possible to do most of this work using netcat I wanted to add more error checking and different abilities to the system so I have written a simple python script. The full source code can be found in my lecture code here

#!/usr/bin/env python

import argparse
import socket
import sys

def send_command(addr: tuple, command: str) -> None:
    """Send a command to Maya through a socket connection.

    Args:
        addr (tuple): Tuple containing host and port (host, port)
        command (str): The command to send to Maya
    """
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
        client.connect(addr)
        client.sendall(command.encode("utf-8"))

def process_mel_command(command: str) -> str:
    """Process MEL command by joining lines and adding newline. Mel is fussy and needs a whole
    line string, unlike the python version.

    Args:
        command (str): The MEL command to process

    Returns:
        str: Processed MEL command
    """
    return ' '.join(line.strip() for line in command.splitlines()) + '\n'

def setup_parser() -> argparse.ArgumentParser:
    """Create and configure the argument parser.

    Returns:
        argparse.ArgumentParser: Configured parser
    """
    parser = argparse.ArgumentParser(
        description="""Send file to Maya on Port. Ensure the port is enabled and you have set the correct values.
        echoOutput must be False for Maya 2022 else you get encode errors. To setup maya use the following:
        cmds.commandPort(name=":7002", sourceType="python", echoOutput=False)
        """
    )

    parser.add_argument(
        "--port", "-p",
        nargs="?",
        default=7001, # default for my setup python
        type=int,
        help="command port to send on default 7890"
    )
    parser.add_argument(
        "--file", "-f",
        nargs="?",
        default="",
        type=str,
        help="file to send"
    )
    parser.add_argument(
        "--host", "-o",
        nargs="?",
        default="localhost",
        type=str,
        help="host, default localhost"
    )
    parser.add_argument(
        "--mel", "-m",
        action='store_true',
        help="sending a mel file as this needs different encoding"
    )

    return parser

def main() -> int:
    parser = setup_parser()
    args = parser.parse_args()

    if args.file:
        with open(args.file, "r") as f:
            command = f.read()
    else: # read from stdin for pipes etc.
        command = "".join(sys.stdin.readlines())
    if args.mel:
        print("Processing MEL command")
        command = process_mel_command(command)

    send_command((args.host, args.port), command)
    return 0

if __name__ == "__main__":
    sys.exit(main())

This program uses argparse to parse command line arguments and we can specify both the port and host as well as an optional file using the -f flag.

If no file is passed then input will be read on stdin, which is useful using things like echo or cat and a pipe | .

I have placed this script into a pathed folder on my machine but you can also run it via a full path. It expects python to be installed, however is is also possible to run this script via the mayapy python as well.

The script can be tested in two way using the existing maya command ports

sendtomaya.py -p 7002 -f [a python file]
# or

cat [a python file] | sendtomaya.py -p 7002

For mel just change the port / file

Linking to Zed

The Zed editor has the ability to generate tasks which can then be bound to keybindings

The task.json file lives in the folder ~/.config/tasks.json if it doesn’t exist you can create one.

I have generated two tasks for python, one to send the whole file to maya and one to send the selected text to maya.

{
    "label": "send python file to maya",
    "command": "sendtomaya.py -p 7002 -f $ZED_FILE",
    "env": {},
    "use_new_terminal": false,
    "allow_concurrent_runs": false,
    "reveal": "always"
  },
  {
    "label": "send selected python to maya",
    "command": "echo \"$ZED_SELECTED_TEXT\" | sendtomaya.py -p 7002",
    "env": {},
    "use_new_terminal": false,
    "allow_concurrent_runs": false,
    "reveal": "always"
  }

I am using two build in variables $ZED_FILE and $ZED_SELECTED_TEXT to send the data to the script. I use two different key binding to send either whole file or selected text. I’m unsure if there is anyway to add logic directly in the tasks, however I may experiment using a simple shell script to check to see if $ZED_SELECTED_TEXT is empty and then send the file.

I have also not bound sending mel code as I don’t code it much, but I may do this in the future. Again it would be good to get some logic here and check the file extension and send depending upon this.

For the key bindings I have added the following to the keymap.json file (also in ~/.config/Zed) as follows

{
  "context": "Workspace",
  "bindings": {
    "cmd-r": "terminal_panel::ToggleFocus",
    "cmd-P": [
      "task::Spawn",
      {
        "task_name": "send python file to maya"
      }
    ],
    "alt-p": [
      "task::Spawn",
      {
        "task_name": "send selected python to maya"
      }
    ]
  }
},

Conclusions

This is working quite well, and I’m really enjoying the simplicity of the Zed editor for programming in both python and C++

I will attempt to update the scripts now to see if I can get some logic into the command that is run via the keypress.

Previous

Related